code

2017年10月30日 星期一

Stanford ios 10 with Swift 筆記6 - Memory Management

ARC (Automatic Reference Counting)

reference types (i.e. classes) 是儲存在heap中,要如何從heap釋放這些不使用的objects?
Java使用garbage collection,但是swift並不使用garbage collection,而是ARC

每次某個object被referenced,ARC就會增加此object的reference count,當然如果reference消失也會減少reference count,一個object的reference count為零的時候,就能從heap中釋放。

ARC是全自動的,programmer不能控制heap release。


影響ARC的方法

strong: 這是標準的reference,也就是某個var / let reference到的object,只在這個var/let 沒用到 (例如也deallocated / out of scope),才會decrease reference count。

weak: 這只能用在 var/let是一個 Optional,因為他的語意是“如果某個object在heap中已經沒有人reference,那就deallocate它吧,我不care。如果還有人reference他,那我就持續weak reference他”。所以是一種消極的reference。當這個object因為沒人reference而被deallocated from heap的話,這個var/let 會被設定成nil,這也是為什麼只能用在Optional的關係。

unowned: 強制設定某個heap中的object不要再做ARC,這個等於破壞了ARC機制,非常少使用,通常用來打破memory cycle situation。

Memory Cycle

這有點類似deadlock,就是兩個object互相strong reference到彼此。


Closures and ARC

closures是一個function object,是一個reference type所以存在heap中,他對他code block中的任何reference types會有strong reference注意這個隱性的事實容易造成memory cycle,如果code block中的reference types又有strong reference到這個enclosing closure的話。

假設有以下一個method:


client ViewController 假設傳入一個closure使用如下:


但是如果closure是trailing parameter,swift允許使用以下syntactic sugar:



甚至更進一步利用type inference簡化:


這樣寫很容易讓人忘記這事實上是一個trailing closure parameter,所以也就忘記了closure會對所有其內的reference types做strong reference。

還好swift compiler不允許這樣被compile,他希望programmer要明確知道這個closure有strong reference to self  (outer class, i.e. ViewController):


注意如果不幸ViewController又有strong reference到這個closure的話,memory cycle 就會形成了!這種現象很可能發生,因為reference關係通常不明顯,需要考慮清楚


解決此memory cycle:
1. 在closure中宣告一個local variable me,指向self (ViewController),這樣當然無助於break memory cycle,因為這又對self增加了一個strong reference(closure -> me -> self)。

不過如果採用unowned宣告me指向的self不要增加reference count:



me被使用的時候,如果self已經不在heap的話,此時就會crash,但是self是一個viewcontroller,所以這個情況crash也是合理的 (也是啦~)

不過為什麼不用weak? 其實用weak是比較preferred way,不過注意weak 一定是Optional才能宣告,所以要用?來防止self真的在heap中被deallocated:




沒有留言:

張貼留言