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