解決實(shí)例之間的循環(huán)強(qiáng)引用
如果兩個(gè)類實(shí)例互相持有對方的強(qiáng)引用(如class1中的某個(gè)屬性是class2,class2中的某個(gè)屬性是class1)矿辽,因而每個(gè)實(shí)例都讓對方一直存在,這就是所謂的循環(huán)強(qiáng)引用航瞭。
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)引用沧奴。
基本策略
- 對于生命周期中會變?yōu)閚il的實(shí)例使用弱引用。
- 對于初始化賦值后再也不會被賦值為nil的實(shí)例长窄,使用無主引用滔吠。
- 第三種場景纲菌,在這種場景中,兩個(gè)屬性都必須有值疮绷,并且初始化完成后永遠(yuǎn)不會為nil翰舌。在這種場景中,需要一個(gè)類使用無主屬性冬骚,而另外一個(gè)類使用隱式解析可選屬性(propertyR渭)。
解決閉包引起的循環(huán)強(qiáng)引用
循環(huán)強(qiáng)引用還會發(fā)生在當(dāng)你將一個(gè)閉包賦值給類實(shí)例的某個(gè)屬性只冻,并且這個(gè)閉包體中又使用了這個(gè)類實(shí)例時(shí)庇麦。這個(gè)閉包體中可能訪問了實(shí)例的某個(gè)屬性,例如self.someProperty喜德,或者閉包中調(diào)用了實(shí)例的某個(gè)方法山橄,例如self.someMethod()。這兩種情況都導(dǎo)致了閉包“捕獲”self舍悯,從而產(chǎn)生了循環(huán)強(qiáng)引用航棱。
解決閉包引起的循環(huán)強(qiáng)引用
在定義閉包時(shí)同時(shí)定義捕獲列表作為閉包的一部分,通過這種方式可以解決閉包和類實(shí)例之間的循環(huán)強(qiáng)引用
注意Swift 有如下要求:只要在閉包內(nèi)使用self的成員萌衬,就要用self.someProperty或者self.someMethod()(而不只是someProperty或someMethod())饮醇。這提醒你可能會一不小心就捕獲了self。
如果閉包有參數(shù)列表和返回類型秕豫,把捕獲列表放在它們前面:
lazy var someClosure: (Int, String) -> String = {
//[ ... ]中為捕獲列表
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
// 這里是閉包的函數(shù)體
}
在閉包中使用unowned朴艰,weak的原則:
- 在閉包和捕獲的實(shí)例總是互相引用并且總是同時(shí)銷毀時(shí),將閉包內(nèi)的捕獲定義為無主引用混移。
- 相反的祠墅,在被捕獲的引用可能會變?yōu)閚il時(shí),將閉包內(nèi)的捕獲定義為弱引用沫屡。
- 如果被捕獲的引用絕對不會變?yōu)閚il,應(yīng)該用無主引用撮珠,而不是弱引用沮脖。