Swift中的迴圈強引用 【使用無主引用解決】

小豬熊發表於2017-12-13

無主引用(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變數,用來儲存某個特定客戶的引用。由於是可選型別,所以變數被初始化為nilvar john: Customer?

現在你可以建立Customer類的例項,用它初始化CreditCard例項,並將新建立的CreditCard例項賦值為客戶的card屬性:

john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
複製程式碼

在你關聯兩個例項後,它們的引用關係如下圖所示:

Swift中的迴圈強引用  【使用無主引用解決】

Customer 例項持有對 CreditCard 例項的強引用,而 CreditCard 例項持有對 Customer 例項的無主引用。

由於 customer 的無主引用,當你斷開 john 變數持有的強引用時,再也沒有指向 Customer 例項的強引用了:

Swift中的迴圈強引用  【使用無主引用解決】
由於再也沒有指向 Customer 例項的強引用,該例項被銷燬了。其後,再也沒有指向 CreditCard 例項的強引用,該例項也隨之被銷燬了:

john = nil
// 列印 “John Appleseed is being deinitialized”
// 列印 ”Card #1234567890123456 is being deinitialized”
複製程式碼

最後的程式碼展示了在john變數被設為nilCustomer例項和CreditCard例項的建構函式都列印出了“銷燬”的資訊。

注意 上面的例子展示瞭如何使用安全的無主引用。對於需要禁用執行時的安全檢查的情況(例如,出於效能方面的原因),Swift還提供了不安全的無主引用。與所有不安全的操作一樣,你需要負責檢查程式碼以確保其安全性。 你可以通過unowned(unsafe)來宣告不安全無主引用。如果你試圖在例項被銷燬後,訪問該例項的不安全無主引用,你的程式會嘗試訪問該例項之前所在的記憶體地址,這是一個不安全的操作。

引自:http://www.piggybear.net/?p=681

相關文章