析構過程
析構過程是構造過程的逆向過程,當乙個類的例項被釋放的時候,在記憶體中消失前,析構器會被呼叫。 原型
deinit
由於swift是arc管理記憶體,所以析構過程已經不像c++那麼重要了。
class myclass
deinit }
var myinstance:myclass? = myclass()
println(myinstance!.mynum)
myinstance = nil
//deinit在此時被自動呼叫
arc
arc機制會跟蹤每乙個例項正在被多少屬性,常量以及變數所引用,只要這個例項的引用數不為0,那麼這個例項就不會被銷毀。那麼它的deinit也不會被呼叫。
文件中,這一章,只講了兩件事兒:
1. 例項之間的迴圈引用是怎麼發生的。
2. 如何消除迴圈引用導致的記憶體洩露。
文件用了滿多的篇幅寫了這兩件事,足以說明,arc並不像想像中那麼美好,雖然不像c/c++中那樣,要求程式設計師用一些精力來管理記憶體,但arc也並沒有把這種精力降低了多少,反而,一切看似美好的東西,導致的難查的bug會更難查。對底層機制隱藏的太多,導致程式設計師的底層思維得不到鍛鍊的結果吧。
這一章,沒什麼太多想說的,管方的**已經比文字表達的要清晰得多了,所以只是留些圖,便於查閱。
下面的**,基於這兩個類。這裡可以看到,兩個類裡都分別有另乙個類的可選型別的變數。那麼,結果就是導致了他們互相持有對方的handle:
懂oo的都知道,這種情況是強關聯。
在arc中,當把john 和 number73都賦值為nil的時候,雖然看似斷掉了john和number73這兩個引用了,但是,在例項中,還有apartment 與 tenant兩個引用沒有斷掉,於是,我們會想到,把這兩個寫到deinit中去,讓他們斷開引用關係:
在person類中的deinit中加入:
apartment = nil
在apartment類中的deinit中加入:
tenant = nil
但是,這樣依然不行,因為在前面我們說過,deinit是在例項被釋放的時候發生的,而例項的釋放又是在arc管理中的例項引用計數為0的時候發生的。所以,deinit並不會被呼叫。這樣就導致了記憶體洩漏。所以,
無論如何,都不可以出現兩個例項互相強引用的情況,必然導致記憶體洩漏。
弱引用
為了解決上面的迴圈強引用,引入乙個叫做「弱引用」的方式,關鍵字是weak:
這樣的話,weak引用,不會阻止arc**例項,也就是說,乙個例項,如果沒有被強引用,哪怕有成百上千個弱引用持有它的話,它依然可以被釋放。(weak可能會導致引用計數不增加?我不知道答案)
無主引用(unowned references)
與剛剛說的弱引用,作用是一樣,但
弱引用是給可選型用的,而
無主引用是給非可選型用的。
閉包導致的迴圈強引用
當htmlelement類的例項在初始化的時候,閉包作為ashtml屬性的預設值,與htmlelement的例項之間建立了強引用關係,也就是我們開始提到無論如何都不要發生的事情。。。。
我們需要讓閉包變成無主引用(前面說過,弱引用是給可選型用的,而這裡閉包明顯不是乙個可選型):
在閉包中,使用
[unowned self] in
總結 從上面的例子可以看得出來,在引用關係中,我們可以分得出上下級關係(類的例項為最上級),
所有的下級引用上級的情況,要麼定義為弱引用(可選型),要麼定義為無主引用,就可以避免迴圈引用而導致的記憶體洩漏。
Swift學習筆記 二十五 析構過程
析構器只適用於類型別,當乙個類的實 被釋放之前,析構 會被立即呼叫。析構 關鍵字 deinit 來標示,類似於構造 要用 init 來標示。swift 會自動釋放 再需要的實 以釋放資源。如 自動引用計數 章節中所講述,swift 通過自動引用計數 arc 處理 實 的 記憶體管 通常當你的實 被釋...
Swift 析構過程
析構器只適用於類型別,當乙個類的例項被釋放之前,析構器會被立即呼叫。析構器用關鍵字deinit來標示,類似於構造器要用init來標示。析構過程原理 swift 會自動釋放不再需要的例項以釋放資源。如自動引用計數章節中所講述,swift 通過自動引用計數 arc 處理例項的記憶體管理。通常當你的例項被...
Swift 析構過程
析構器只適用於類型別,當乙個類的例項被釋放之前,析構器會被立即呼叫。析構器的關鍵字deinit來標示,類似於構造器要用init來標示。swift會自動釋放不再需要的例項以釋放資源。swift通過自動引入計數處理例項的記憶體管理。通常當你的例項被釋放時不惜要手動去清理。但是,當使用自己的資源時,你可能...