Swift 提供了兩種辦法用來解決你在使用類的屬性時所遇到的循環(huán)強引用問題:弱引用(weak reference)和無主引用(unowned reference)。
弱引用和無主引用允許循環(huán)引用中的一個實例引用另外一個實例而不保持強引用。這樣實例能夠互相引用而不產(chǎn)生循環(huán)強引用。
對于生命周期中會變?yōu)?code style="box-sizing: border-box; -webkit-tap-highlight-color: transparent; -webkit-font-smoothing: antialiased; font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 14px; padding: 0px 5px; color: rgb(199, 37, 78); background-color: rgb(248, 248, 248); white-space: nowrap; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; margin: 0px 2px; border: 1px solid rgb(234, 234, 234);">nil的實例使用弱引用。相反的,對于初始化賦值后再也不會被賦值為nil的實例,使用無主引用。
弱引用不會牢牢保持住引用的實例,并且不會阻止 ARC 銷毀被引用的實例。這種行為阻止了引用變?yōu)檠h(huán)強引用。聲明屬性或者變量時,在前面加上weak關(guān)鍵字表明這是一個弱引用。
在實例的生命周期中,如果某些時候引用沒有值,那么弱引用可以阻止循環(huán)強引用。如果引用總是有值,則可以使用無主引用,在無主引用中有描述。在上面Apartment的例子中,一個公寓的生命周期中,有時是沒有“居民”的,因此適合使用弱引用來解決循環(huán)強引用。
注意:
弱引用必須被聲明為變量,表明其值能在運行時被修改。弱引用不能被聲明為常量。
因為弱引用可以沒有值,你必須將每一個弱引用聲明為可選類型。可選類型是在 Swift 語言中推薦的用來表示可能沒有值的類型。
因為弱引用不會保持所引用的實例,即使引用存在,實例也有可能被銷毀。因此,ARC 會在引用的實例被銷毀后自動將其賦值為nil。你可以像其他可選值一樣,檢查弱引用的值是否存在,你永遠也不會遇到被銷毀了而不存在的實例。
下面的例子跟上面Person和Apartment的例子一致,但是有一個重要的區(qū)別。這一次,Apartment的tenant屬性被聲明為弱引用:
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { println("\(name) is being deinitialized") }
}
class Apartment {
let number: Int
init(number: Int) { self.number = number }
weak var tenant: Person?
deinit { println("Apartment #\(number) is being deinitialized") }
}
然后跟之前一樣,建立兩個變量(john和number73)之間的強引用,并關(guān)聯(lián)兩個實例:
var john: Person?
var number73: Apartment?
john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)
john!.apartment = number73
number73!.tenant = john
現(xiàn)在,兩個關(guān)聯(lián)在一起的實例的引用關(guān)系如下圖所示:

Person實例依然保持對Apartment實例的強引用,但是Apartment實例只是對Person實例的弱引用。這意味著當你斷開john變量所保持的強引用時,再也沒有指向Person實例的強引用了:

由于再也沒有指向Person實例的強引用,該實例會被銷毀:
john = nil
// prints "John Appleseed is being deinitialized"
唯一剩下的指向Apartment實例的強引用來自于變量number73。如果你斷開這個強引用,再也沒有指向Apartment實例的強引用了:

由于再也沒有指向Apartment實例的強引用,該實例也會被銷毀:
number73 = nil
// prints "Apartment #73 is being deinitialized"
上面的兩段代碼展示了變量john和number73在被賦值為nil后,Person實例和Apartment實例的析構(gòu)函數(shù)都打印出“銷毀”的信息。這證明了引用循環(huán)被打破了。
和弱引用類似,無主引用不會牢牢保持住引用的實例。和弱引用不同的是,無主引用是永遠有值的。因此,無主引用總是被定義為非可選類型(non-optional type)。你可以在聲明屬性或者變量時,在前面加上關(guān)鍵字unowned表示這是一個無主引用。
由于無主引用是非可選類型,你不需要在使用它的時候?qū)⑺归_。無主引用總是可以被直接訪問。不過 ARC 無法在實例被銷毀后將無主引用設(shè)為nil,因為非可選類型的變量不允許被賦值為nil。
注意:
如果你試圖在實例被銷毀后,訪問該實例的無主引用,會觸發(fā)運行時錯誤。使用無主引用,你必須確保引用始終指向一個未銷毀的實例。
還需要注意的是如果你試圖訪問實例已經(jīng)被銷毀的無主引用,程序會直接崩潰,而不會發(fā)生無法預(yù)期的行為。所以你應(yīng)當避免這樣的事情發(fā)生。
下面的例子定義了兩個類,上一篇:Swift變量聲明下一篇:Swift Any和AnyObject類型轉(zhuǎn)換