Swift 提供了兩種辦法用來解決你在使用類的屬性時(shí)所遇到的循環(huán)強(qiáng)引用問題:弱引用(weak reference)和無主引用(unowned reference)。
弱引用和無主引用允許循環(huán)引用中的一個(gè)實(shí)例引用另外一個(gè)實(shí)例而不保持強(qiáng)引用。這樣實(shí)例能夠互相引用而不產(chǎn)生循環(huán)強(qiáng)引用。
對于生命周期中會(huì)變?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的實(shí)例使用弱引用。相反的,對于初始化賦值后再也不會(huì)被賦值為nil的實(shí)例,使用無主引用。
弱引用不會(huì)牢牢保持住引用的實(shí)例,并且不會(huì)阻止 ARC 銷毀被引用的實(shí)例。這種行為阻止了引用變?yōu)檠h(huán)強(qiáng)引用。聲明屬性或者變量時(shí),在前面加上weak關(guān)鍵字表明這是一個(gè)弱引用。
在實(shí)例的生命周期中,如果某些時(shí)候引用沒有值,那么弱引用可以阻止循環(huán)強(qiáng)引用。如果引用總是有值,則可以使用無主引用,在無主引用中有描述。在上面Apartment的例子中,一個(gè)公寓的生命周期中,有時(shí)是沒有“居民”的,因此適合使用弱引用來解決循環(huán)強(qiáng)引用。
注意:
弱引用必須被聲明為變量,表明其值能在運(yùn)行時(shí)被修改。弱引用不能被聲明為常量。
因?yàn)槿跻每梢詻]有值,你必須將每一個(gè)弱引用聲明為可選類型??蛇x類型是在 Swift 語言中推薦的用來表示可能沒有值的類型。
因?yàn)槿跻貌粫?huì)保持所引用的實(shí)例,即使引用存在,實(shí)例也有可能被銷毀。因此,ARC 會(huì)在引用的實(shí)例被銷毀后自動(dòng)將其賦值為nil。你可以像其他可選值一樣,檢查弱引用的值是否存在,你永遠(yuǎn)也不會(huì)遇到被銷毀了而不存在的實(shí)例。
下面的例子跟上面Person和Apartment的例子一致,但是有一個(gè)重要的區(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") }
}
然后跟之前一樣,建立兩個(gè)變量(john和number73)之間的強(qiáng)引用,并關(guān)聯(lián)兩個(gè)實(shí)例:
var john: Person?
var number73: Apartment?
john = Person(name: "John Appleseed")
number73 = Apartment(number: 73)
john!.apartment = number73
number73!.tenant = john
現(xiàn)在,兩個(gè)關(guān)聯(lián)在一起的實(shí)例的引用關(guān)系如下圖所示:

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

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

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