【Swift記憶體管理】strong VS weak VS unowned

在ARC下,讓開發者對記憶體管理,省下很功夫,同時也減少不必要的bug,讓成APP閃退。但在某些情境,仍需開發者費心,把變數宣告成weak或unowned,避免retain cycle。本篇文章,帶大家認識strong、weak和unowned差別。

陳仕偉
6 min readJun 28, 2021

strong VS weak VS unowned

  • 在ARC下,變數預設是strong reference
  • strong:對引用物件,reference count會累加
  • weak和unowned:對引用物件,reference count不會累加

weak:當指向的物件不存在時,會被設成nil,所以宣告變數必須是可選型別(optional type)

unowned:一定要非可選型別(non-optional type),才不會引發指向物件不存時,對unowned變數存取,導致runtime error

weak的變數不能用 let 宣告,因為它有可能變成nil,但常數不允許被修改

Memory Leak

如何造成memory leak

當兩個物件互相引用時,會造成retain cycle (strong reference cycle),該被回收物件,無法從記憶體中釋放,導致memory leak發生。

程式碼範例

class Person {
var name: String
var device: Device?
init(name: String) {
self.name = name
print("Person is being initialized.")
}
deinit {
print("Person is being deinitialized.")
}
}
class Device {
var name: String
var owner: Person?
init(name: String) {
self.name = name
print("Device is being initialized.")
}
deinit {
print("Device is being deinitialized.")
}
}
var eric: Person? = Person(name: "Eric")
var iphoneXR: Device? = Device(name: "iPhone XR")
eric?.device = iphoneXR
iphoneXR?.owner = eric
eric = nil
iphoneXR = nil

Referece Counting 過程

執行結果

Person和Device的「deinit」沒有被執行

Person is being initialized.
Device is being initialized.

Person引用Device,而Device也引用Person,互相引用對方,無法從記憶體釋放,造成了memory leak (記憶體洩漏) 問題。

如何解決memory leak

用weak或unowned去修飾宣告變數,就不會對引用物件,累加reference counting

class Device {
var name: String
weak var owner: Person? init(name: String) {
self.name = name
print("Device is being initialized.")
}
deinit {
print("Device is being deinitialized.")
}
}

Reference Counting 過程

執行結果

Person和Device都被回收

Person is being initialized.
Device is being initialized.
Person is being deinitialized.
Device is being deinitialized.

--

--

陳仕偉
陳仕偉

No responses yet