Automatic Reference Counting
迴圈引用(strong reference cycles)
1、程式碼示例:
class Person {
let name: String
init(name: String) { self.name = name }
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
var john: Person?
var unit4A: Apartment?
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
//雖然你置為nil,但是這兩個類的例項並沒有釋放記憶體,沒有執行print語句
john = nil
unit4A = nil複製程式碼
2、兩種解決辦法:
- 當其他的例項有更短的生命週期的時候,使用weak
- 當其他的例項有相同的或者更長的生命週期的時候,使用unowened
3、weak和unowened的使用
- weak的使用
將上述程式碼的Apartment中的Person例項前新增weak關鍵字,在執行上述程式碼就會執行print
weak var tenant: Person?複製程式碼
- unowened的使用
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit { print("\(name) is being deinitialized") }
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit { print("Card #\(number) is being deinitialized") }
}
var john: Customer?
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
john = nil
// Prints "John Appleseed is being deinitialized"
// Prints "Card #1234567890123456 is being deinitialized"複製程式碼
閉包的迴圈引用(strong references for closures)
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
paragraph = nil//不會執行print複製程式碼
可以定義capture list來解決
//有引數
lazy var someClosure: (Int, String) -> String = {
[unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in
// closure body goes here
}
//無引數
lazy var someClosure: () -> String = {
[unowned self, weak delegate = self.delegate!] in
// closure body goes here
}複製程式碼
修改上述例子後的程式碼:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
paragraph = nil//執行print複製程式碼
Tip:
- ARC只是用於類,不適用於結構體和列舉
- 當ARC設定的weak引用指為nil時,屬性觀察者不會被呼叫
- 當你在確定引用的例項永遠不會銷燬的時候,使用unowened,如果你想訪問被釋放的owened屬性,你會遇到執行時錯誤。
- owened有安全和不安全兩種模式,上面示例中為安全模式,你可以使用unowned(unsafe)來實現不安全模式。如果你試圖訪問被釋放的不安全指向的例項,你的程式將會訪問該例項曾經儲存的記憶體地址,這是一個不安全的操作