【Swift4.2】循環引用的例子講解
阿新 • • 發佈:2018-12-20
div 例子 uno tar deinit 實例 func blog 循環
最近又想回顧下swift,現在版本已經到4.2了。。。想當時15年,我寫swift2.1的時候,我遇到了很多讓我感到尷尬的場景。。
https://www.cnblogs.com/rayshen/p/5038937.html
這邊博客現在看起來還非常搞笑,但是當時確實是這樣。好在我之前說的這些問題,在後來的swift版本中,都已經給糾正過來了(感覺swift語言組也好水)……
這次要回顧的是循環引用,這個是老生常談的問題。在block和delegate中,如果兩個對象A和B,A強引用B,B又強引用A時,A的引用計數就會變成2,這樣就會造成A無法自動釋放。
看一段示例代碼:
class Example{ private var name = "123"; /// 正確用法1 lazy private var rightClosure1:()->() = { [unowned self] in print("name is \(self.name)") } /// 正確用法2 lazy private var rightClosure2:()->() = { [weak self] in print("name is \(self?.name ?? "")") } /// 函數用法不存在該問題 private func commonFunction(){ print("name is \(self.name)") } /// 錯誤用法 lazy private var errorCycleClosure1:()->() = { print("name is \(self.name)") } /// 錯誤用法(函數賦值給errorCycleClosure2,errorCycleClosure2變成一個閉包對象被引用,函數是這個閉包的實現)lazy private var errorCycleClosure2 = commonFunction; func startRight1() { rightClosure1() } func startRight2() { rightClosure2() } func startRight3() { commonFunction() } func startError1() { errorCycleClosure1() } //需要特殊警惕的情況,一旦函數被賦值給一個被引用的對象後,也會出現循環引用的情況 func startError2() { errorCycleClosure2() } deinit{ print("Example deinit") } } var example:Example? = Example() //調用正確例子1,example=nil後能正常銷毀 //example?.startRight1(); //調用正確例子2,example=nil後能正常銷毀 //example?.startRight2(); //調用正確例子3,example=nil後能正常銷毀(函數不存在循環引用問題) //example?.startRight3(); //調用錯誤例子1,example=nil後沒有調用deinit,說明有殘留成員變量 //example?.startError1(); //調用錯誤例子2,example=nil後沒有調用deinit,說明有殘留成員變量 example?.startError2(); example=nil;
這裏面有幾個swift的知識點:
1.lazy的用法:所謂的lazy就是懶加載,在沒有被getter訪問時,他不進行初始化。在這裏,一個閉包初始化中訪問到self,因為self在此時還沒生成所以需要添加lazy修飾,使他們在被訪問到時才初始化。
2.[unowned self]和[weak self]和區別: [unowned self]調用closure的時候如果對象已經被釋放的話,會出現crash。
3.為什麽函數直接調用沒影響:因為函數在內存中只分配函數地址,不是一個對象。而閉包是一個對象,是個引用類型,會被實例對象所引用,如果閉包再引用實例對象本身,就會出現循環引用。
【Swift4.2】循環引用的例子講解