無主引用(unowned)
聲明屬性或者變量時,在前面加上unowned關鍵字表示這是一個無主引用,無主引用不能設置為nil,因為非可選類型的變量不允許被賦值為nil。
兩個屬性,其中一個為可選類型,另外一個不是可選類型,而且相互引用,這種情況下一般使用無主引用去解決循環強引用。
案例
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
注意
CreditCard
類的number
屬性被定義為UInt64
類型而不是Int
類型,以確保number
屬性的存儲量在 32 位和 64 位系統上都能足夠容納 16 位的卡號。
下面的代碼片段定義了一個叫john
的可選類型Customer
變量,用來保存某個特定客戶的引用。由于是可選類型,所以變量被初始化為nil
:
var john: Customer?
現在你可以創建Customer
類的實例,用它初始化CreditCard
實例,并將新創建的CreditCard
實例賦值為客戶的card
屬性:
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
在你關聯兩個實例后,它們的引用關系如下圖所示:
Customer
實例持有對 CreditCard
實例的強引用,而 CreditCard
實例持有對 Customer
實例的無主引用。
由于 customer
的無主引用,當你斷開 john
變量持有的強引用時,再也沒有指向 Customer
實例的強引用了:
由于再也沒有指向
Customer
實例的強引用,該實例被銷毀了。其后,再也沒有指向 CreditCard
實例的強引用,該實例也隨之被銷毀了:
john = nil
// 打印 “John Appleseed is being deinitialized”
// 打印 ”Card #1234567890123456 is being deinitialized”
最后的代碼展示了在john
變量被設為nil
后Customer
實例和CreditCard
實例的構造函數都打印出了“銷毀”的信息。
注意
上面的例子展示了如何使用安全的無主引用。對于需要禁用運行時的安全檢查的情況(例如,出于性能方面的原因),Swift還提供了不安全的無主引用。與所有不安全的操作一樣,你需要負責檢查代碼以確保其安全性。 你可以通過unowned(unsafe)來聲明不安全無主引用。如果你試圖在實例被銷毀后,訪問該實例的不安全無主引用,你的程序會嘗試訪問該實例之前所在的內存地址,這是一個不安全的操作。