在 Swift 中,unowned 和 weak 都是用来解决循环引用问题的。
循环引用指的是两个对象相互持有对方的强引用,导致它们都无法被释放,从而造成内存泄露。例如,当一个对象持有一个闭包,而该闭包又持有该对象时,就会形成循环引用。
为了解决这个问题,Swift 提供了两种解决方案:unowned 和 weak。
unowned 与 weak 都可以解决循环引用问题,但它们之间有一些区别:
- unowned 属性必须有值,不能为 nil,而 weak 属性可以为 nil。
- unowned 属性在对象释放时不会被自动置为 nil,访问已释放的对象会导致程序崩溃,而 weak 属性在对象释放时会被自动置为 nil。
- unowned 属性一旦设定,就不会再变化,而 weak 属性可以在运行时被修改。
下面是一个使用 unowned 和 weak 的示例:
class Person {
var name: String
var car: Car?
lazy var printName: () -> () = {
[unowned self] in
print(self.name)
}
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
class Car {
var brand: String
weak var owner: Person?
init(brand: String) {
self.brand = brand
print("\(brand) is being initialized")
}
deinit {
print("\(brand) is being deinitialized")
}
}
var john: Person?
var benz: Car?
john = Person(name: "John")
benz = Car(brand: "Benz")
john!.car = benz
benz!.owner = john
john!.printName() // John
john = nil
benz = nil
// 输出:
// John is being initialized
// Benz is being initialized
// John
// John is being deinitialized
// Benz is being deinitialized
在这个例子中,Person 对象持有一个 Car 对象,而 Car 对象又持有一个 Person 对象,形成了循环引用。为了解决这个问题,我们使用 unowned 和 weak 来打破循环引用。
在 Person 类中,我们定义了一个 lazy 属性 printName,它是一个闭包,用来打印人名。由于该闭包持有 Person 对象,所以它也会造成循环引用。为了解决这个问题,我们使用了 unowned self,即该闭包对 self 对象使用无主引用。
在 Car 类中,我们定义了一个 weak 属性 owner,用来持有 Person 对象。由于 Car 对象可能比 Person 对象先被释放,所以我们使用 weak 引用,以防止访问已经被释放的 Person 对象。
最后,我们将 john 和 benz 变量设为 nil,以释放它们所持有的对象。输出结果表明,对象被成功地释放了,没有造成内存泄露。