基础知识
对象分为三种引用类方式 分别为 strong weak unowned 对象默认引用方式为 strong。strong 对象赋值时引用计数器加一 weak 和 unowned 对象赋值时引用计数器值不变,weak 类型定义时必须是optional 或者是 强制解包类型,unowned 对象必须要有默认值。
swift 闭包(closure)中定义在closure 外的对象引用计数器自动加一。
循环引用
weak引用
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
//图二
当设置 john 与 unit4A 为nil 时 john 和 unit4A 引用计数器都是1 对象不会被删除。
john = nil
unit4A = nil
解决方案
在类定义时外部引用的成员变量设置成weak
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 }
weak 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
//图4
john = nil
//图5
unit4A = nil
//图6
unowned 引用
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!)
//图7
john = nil
//图8
john 对象设置为nil ,john引用计数器为0 john被析构,john.card引用计数器也为0 john 也被析构。
闭包引起的强引用循环
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")
}
}
let heading = HTMLElement(name: "h1")
let defaultText = "some default text"
heading.asHTML = {
return "<\(heading.name)>\(heading.text ?? defaultText)</\(heading.name)>"
}
print(heading.asHTML())
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
print(paragraph!.asHTML())
//closure 使用 closure 外部的对象时 外部对象的引用计数器+1
//图9
解决方案
//定义closure时
lazy var asHTML: () -> String = {[weak self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
//或者
lazy var asHTML: () -> String = {[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
unowned 与weak 的区别
上面的例子 如果设置为weak 当外部的对象self 在closure内是一个optional 类型 设置为unowned closure 内部维持原状
对象内部的closure 的生命周期比对象本身的周期时间长 建议不要使用unowned 使用weak