Swift weak 和 lazy 修飾字
這兩個修飾字雖沒有相對的關係,但嚴格來說確都跟記憶體管理有著一點關係,記憶體管理在程式開發一直以來都是一個很重要的議題,若是沒有好好的妥善管理,可是會導致應用程式緩慢,嚴重的話還會閃退的,所以,在撰寫程式的過程中,如何善用一些技巧來防止記憶體洩露就顯得格外重要😀。所以,法蘭克就要來介紹如何使用這兩個修飾字來解決記憶體洩露和節省記憶體的使用。
weak
weak 僅能修飾 被宣告為 optional 的屬性
,被 weak 修飾的 reference counting 並不會增加
。在實際開發上,常會在宣告 delegate 的 property 或是 closure 的 capture list 時皆可看到其蹤影,其目的就是為了不讓物件與物件之間互相參考而造成retain cycle
而引發memory leak(記憶體洩漏)

法蘭克就來製造出 class 和 class
還有 closure
的 retain cycle,並使用 weak 解決,最後,再用 Xcode 的 instrument 查看 memory leak 的地方。
class 和 class 的 retain cycle
使用 UML 繪製出第 16~20 行的示意圖,John 和 Mary 是愛人,所以彼此互相深愛(參考)著對方。

接下來讓 John 死掉(記憶體釋放),因為 weak 的關係,所以 John 死也瞑目了(deinit()被呼叫)。最後,讓 Mary 也死掉(記憶體釋放),這時侯也因為 weak 的關係,所以 Mary 也死也瞑目了。
closure 的 retain cycle
這段程式碼會造成 closure 的 retain cycle,當 frank = nil 時,Deinit() 確沒有被執行。原因是因為第 6 行的 closure 被存放在 property,也因為如此而增加了 Man 的 reference counting。
要如何修改這段程式才不會造成 retain cycle 呢?很簡單,只要在 closure 加上 capture list 即可。
在第 6 ~ 9 行加入 capture list 的邏輯,使得在第 20 行執行時,Deinit() 被呼叫了。
其實 Xcode 有內建的工具且有兩種方式可用來查看是否有 memory leak 的問題,以下就使用上述 class 和 class 的 retain cycle 分別來說明如何使用它們。在開始之前,為了演示 leak 的狀況,請將變數 lover 前的 weak 修飾字拿掉,意指此 property 為 strong reference。

- 透過「Debug Memory Graph」來查看。
接著執行模擬器後,點選「Debug Memory Graph」

接著點選左側選單下面的「Show only leaked block」

接著就會看到兩個 leaked 物件,如此就可以很清楚的了解有哪些物件沒被釋放掉了。

最後試著再把 weak 修飾字加回去再執行看看結果為何?
2. 透過 Profile 來查看。
在還沒啟動模擬器之前,選取 Profile

選擇 Leaks

接著點選 command + R 來啟動模擬器,啟動後將會看到有兩個 leaked 的物件

lazy
延遲載入,僅能 修飾 var 的屬性
且 一定要有初始值
。有加上 lazy 修飾字的變數它所參考到的 property 並不會立刻生成,而是當開始操作該 property 時才會進行初始。
第 1 ~ 4 行 => 計算工作年資的複雜函式 。
第 11 ~ 14 行 => 建構子,因為在第 9 行有宣告為 lazy,所以在第 13 行並不會立即生成。
其 lazy 的使用情境為何?
- 在高複雜度的 stored property 前提下,該 property 有可能不會被使用到。
- 在高複雜度的 stored property 前提下,該 property 會影響畫面的載入速度。
如果您喜歡我的文章,請多按幾下「拍手」給我鼓勵,或是按「follow」讓我持續提供好文章給您。