Swift解决【闭包引起的循环强引用】
循環(huán)強(qiáng)引用還會發(fā)生在當(dāng)你將一個閉包賦值給類實例的某個屬性,并且這個閉包體中又使用了這個類實例時。這個閉包體中可能訪問了實例的某個屬性,例如self.someProperty,或者閉包中調(diào)用了實例的某個方法,例如self.someMethod()。這兩種情況都導(dǎo)致了閉包“捕獲”self,從而產(chǎn)生了循環(huán)強(qiáng)引用。
解決閉包引起的循環(huán)強(qiáng)引用
在定義閉包時同時定義捕獲列表作為閉包的一部分,通過這種方式可以解決閉包和類實例之間的循環(huán)強(qiáng)引用。捕獲列表定義了閉包體內(nèi)捕獲一個或者多個引用類型的規(guī)則。跟解決兩個類實例間的循環(huán)強(qiáng)引用一樣,聲明每個捕獲的引用為弱引用或無主引用,而不是強(qiáng)引用。應(yīng)當(dāng)根據(jù)代碼關(guān)系來決定使用弱引用還是無主引用。
注意 Swift 有如下要求:只要在閉包內(nèi)使用self的成員,就要用self.someProperty或者self.someMethod()(而不只是someProperty或someMethod())。這提醒你可能會一不小心就捕獲了self。
定義捕獲列表
捕獲列表中的每一項都由一對元素組成,一個元素是weak或unowned關(guān)鍵字,另一個元素是類實例的引用(例如self)或初始化過的變量(如delegate = self.delegate!)。這些項在方括號中用逗號分開。
如果閉包有參數(shù)列表和返回類型,把捕獲列表放在它們前面:
lazy var someClosure: (Int, String) -> String = {[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in// 這里是閉包的函數(shù)體 } 復(fù)制代碼如果閉包沒有指明參數(shù)列表或者返回類型,即它們會通過上下文推斷,那么可以把捕獲列表和關(guān)鍵字in放在閉包最開始的地方:
lazy var someClosure: Void -> String = {[unowned self, weak delegate = self.delegate!] in// 這里是閉包的函數(shù)體 } 復(fù)制代碼弱引用和無主引用
在閉包和捕獲的實例總是互相引用并且總是同時銷毀時,將閉包內(nèi)的捕獲定義為無主引用。
相反的,在被捕獲的引用可能會變?yōu)閚il時,將閉包內(nèi)的捕獲定義為弱引用。弱引用總是可選類型,并且當(dāng)引用的實例被銷毀后,弱引用的值會自動置為nil。這使我們可以在閉包體內(nèi)檢查它們是否存在。
注意 如果被捕獲的引用絕對不會變?yōu)閚il,應(yīng)該用無主引用,而不是弱引用。
案例
class HTMLElement {let name: Stringlet text: String?lazy var asHTML: Void -> String = {[unowned self] inif let text = self.text {return "<\(self.name)>\(text)</\(self.name)>"} else {return "<\(self.name) />"}}init(name: String, text: String? = nil) {self.name = nameself.text = text}deinit {print("\(name) is being deinitialized")}} 復(fù)制代碼捕獲列表是[unowned self],表示“將self捕獲為無主引用而不是強(qiáng)引用”。
創(chuàng)建并打印HTMLElement實例:
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world") print(paragraph!.asHTML()) // 打印 “<p>hello, world</p>” 復(fù)制代碼使用捕獲列表后引用關(guān)系如下圖所示:
這一次,閉包以無主引用的形式捕獲self,并不會持有HTMLElement實例的強(qiáng)引用。如果將paragraph賦值為nil,HTMLElement實例將會被銷毀,并能看到它的析構(gòu)函數(shù)打印出的消息: paragraph = nil // 打印 “p is being deinitialized” 復(fù)制代碼引自:http://www.piggybear.net/?p=690
轉(zhuǎn)載于:https://juejin.im/post/5a312c936fb9a0450f21f062
總結(jié)
以上是生活随笔為你收集整理的Swift解决【闭包引起的循环强引用】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络应用框架Netty快速入门
- 下一篇: laravel数据迁移问题