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 = ericeric = 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.