在 Swift 中,strong、weak 和 unowned 是用于管理引用类型(如类实例)内存的关键字,它们的核心区别在于对引用计数(ARC)的影响和如何处理循环引用。以下是详细总结:
1. 核心区别
| 关键字 | 引用计数 | 是否可为 nil | 使用场景 |
|---|---|---|---|
strong | 增加引用计数 | 否(默认行为) | 默认所有权关系,需要确保对象存活时使用。 |
weak | 不增加引用计数 | 是(自动置 nil) | 避免循环引用,且允许对象为 nil(如委托模式)。 |
unowned | 不增加引用计数 | 否(访问已释放对象会崩溃) | 对象生命周期严格一致时使用(如父子依赖)。 |
2. 何时使用 unowned?
-
使用场景:当两个对象的生命周期严格绑定,且一个对象的销毁必然导致另一个对象无法存在时。
- 例如:信用卡(
CreditCard)不能独立于客户(Customer)存在,此时CreditCard对Customer的引用应为unowned。
- 例如:信用卡(
-
闭包中的使用:如果闭包和捕获的实例生命周期相同(闭包不会在实例销毁后执行),可用
unowned self。class MyClass { func doSomething() { someAsyncTask { [unowned self] in self.doSomethingElse() // 假设闭包不会在 self 释放后执行 } } }
3. 对比示例
循环引用问题
class A {
var b: B?
}
class B {
// 强引用会导致循环(A → B → A)
var a: A?
}
解决方案:
-
使用
weak(当引用可为nil时):class B { weak var a: A? // 打破循环 } -
使用
unowned(当引用不可为nil时):class CreditCard { unowned let owner: Customer // 信用卡必须有持有者 }
4. 注意事项
weak必须声明为可选类型(var+ 可选),因为 ARC 会自动将其置nil。unowned类似非可选的weak,但需确保对象不会被提前释放,否则访问会触发运行时错误。- 闭包捕获列表:优先用
weak处理可能延迟执行的闭包,用unowned仅当闭包与实例生命周期完全一致。
总结
strong:默认行为,用于需要保持对象存活的场景。weak:解决循环引用,允许对象为nil(如委托、闭包可能延迟执行时)。unowned:解决循环引用,用于对象生命周期严格绑定的场景(需确保不会访问已释放对象)。