名詞定義:
ARC:
自動引用計數(Automatic Reference Counting)是編譯器的記憶體管理功能,為Objective-C和Swift提供自動引用計數。 在運行時增加和減少 reference counting,當class instances的reference count達到0時釋放這些class instances。
Strong reference:
當宣告一個class instance 給一個屬性時,預設為Strong reference,reference count 增加。
Weak reference(weak & unowned):
保護不了所指 class instance 不被ARC回收的 reference,weak reference 不能讓reference count 增加。
Example:
下圖是簡單的 reference cycle 示意圖,變數 John 跟 unit4A 各別指向各自的 instance,而john 的屬性 apartment 指向 unit4A instance,而 unit4A 的屬性 tenant 也指向 john instance ,所以目前 john instance跟 unit4A 的 reference count 都是2。
現在把 john 跟 unit4A 變數設為nil:
現在 john 跟 unit4A 的 instance 都無法被存取到,但兩者的 instance 因為 reference count 都還各是1 無法釋放,造成memory leak。
使用 Weak reference 解決,將 Apartment 的 tenant 宣告為weak打破strong reference cycle:
weak var tenant: Person?
現在將 john = nil
因為John 的 instance 只剩unit4A 的 tenant 指向,但 tenant 是 weak reference, reference count 不會增加,所以 john instance 的 reference count = 0, john instance 被釋放。
Unowned 跟 weak 一樣都是weak reference 不同的地方在:
IMPORTANT
Use an unowned reference only when you are sure that the reference always refers to an instance that has not been deallocated.
If you try to access the value of an unowned reference after that instance has been deallocated, you’ll get a runtime error.
使用 unowned 只有當你確認 當一個 reference 在他的生命週期中不會變為 nil ,反之使用weak。
在實際開發時最常遇到 retain cycle 的地方是在使用 closure 跟 delegate 時。
使用 closure 時,如果 body 裡面有用到 self 會使 closure capture 到擁有這個 closure 的 instance 例如下圖:
使用unowned 去打破 cycle :(由於 只有當paragraph 這個 instance 存在才有可能使用 closure asHTML,所以可以使用unowned):
Delegate 舉最常用到的TableView Delegate 當範例
當ViewController擁有tableView而 tableView 的 delegate 設為 self 擁有ViewController 如下圖:
VC: ViewController
S: Strong reference
W: Weak reference
在Apple Developer Documentation 中也可以看到UITableView 的 delegate 是宣告為weak reference 來打破 cycle: