Swift 自動參考計數 (ARC)

Swift 使用 自動參考計數 (Automatic Reference Counting, ARC) 機制來追蹤和管理你的應用程式的記憶體使用。

簡單來說,ARC 會自動幫你管理記憶體,當一個實例不再被需要時,它會自動釋放記憶體。

ARC 如何運作

每次你將一個 Class 實例賦值給一個變數、常數或屬性時,ARC 就會將該實例的「參考計數」加 1。只要引用次數大於 0,該實例就不會被銷毀。

當引用次數變成 0 時,記憶體就會被回收。

循環參考 (Strong Reference Cycles)

雖然 ARC 很聰明,但有時候會出現兩個物件互相持有對方 (A 持有 B, B 也持有 A),導致引用次數永遠不會變成 0,記憶體永遠無法釋放。這就是記憶體洩漏 (Memory Leak)

解決方案 1:弱參考 (Weak References)

使用 weak 關鍵字。弱參考不會增加參考計數。

因為弱參考指向的物件可能隨時被釋放,所以 weak 變數必須是 Optional 的。當物件被銷毀時,ARC 會自動將 weak 變數設為 nil

class Person {
    var apartment: Apartment?
    deinit { print("Person 被釋放") }
}

class Apartment {
    // 使用 weak 打破循環參考
    weak var tenant: Person?
    deinit { print("Apartment 被釋放") }
}

解決方案 2:無主參考 (Unowned References)

使用 unowned 關鍵字。和 weak 一樣不會增加計數。

主要區別是:unowned 引用假定該物件永遠有值 (非 Optional)。如果被引用的物件釋放了,你還嘗試存取 unowned 變數,程式會當機。因此,只在你確定該物件的生命週期比持有者更長時才使用。

閉包中的循環參考

閉包也是參考型別,如果在物件內部使用閉包且閉包又引用了 self,也會造成循環參考。

解決方法是使用 Capture List

lazy var someClosure: () -> String = { [weak self] in
    // 使用 [weak self],self 會變成 Optional
    return "Hello, \(self?.name ?? "Guest")"
}

這在開發 iOS App (尤其是使用 Delegate 或 Closure callback) 時是非常重要的概念。