保留环及使用 weak/unowned 打破它们
识别对象与闭包之间的保留环,然后安全地使用 weak 和 unowned 引用打破它们。
保留环及使用 weak/unowned 打破它们 是 CoddyKit 上的免费 Swift Academy 课时。 这是第 2 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Swift Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Swift Academy 课程共包含 3 节课。
什么是保留环?
当对象(或闭包)彼此持有强引用,使 ARC 永远无法将计数降至零时,就会形成保留环。请使用弱引用或无主引用打破循环。
对象 ↔ 对象循环
两个方向上的强引用会造成内存泄漏:两个对象的计数都无法降至零。
final class Owner {
var gadget: Gadget?
deinit { print("Owner deinit") }
}
final class Gadget {
var owner: Owner?
deinit { print("Gadget deinit") }
}
// Strong ⇄ strong (cycle)
var o: Owner? = Owner()
var g: Gadget? = Gadget()
o!.gadget = g
g!.owner = o
o = nil // no deinit
g = nil // still no deinit (leak)用弱引用打破循环
将其中一侧设为弱引用(通常是类似委托/Owner 的回指),即可让 ARC 释放两个对象。
final class Owner2 {
var gadget: Gadget2?
deinit { print("Owner2 deinit") }
}
final class Gadget2 {
weak var owner: Owner2? // weak breaks cycle; becomes nil automatically
deinit { print("Gadget2 deinit") }
}
var o2: Owner2? = Owner2()
var g2: Gadget2? = Gadget2()
o2!.gadget = g2
g2!.owner = o2
o2 = nil // Owner2 deinit
g2 = nil // Gadget2 deinit闭包循环(强引用 self)
闭包默认会强引用捕获变量。如果对象同时拥有这个闭包,就会形成循环。
final class TimerClient {
var tick: (() -> Void)?
deinit { print("TimerClient deinit") }
func start() {
// BAD: closure strongly captures self; self keeps tick strongly
tick = {
print("tick from", self) // strong capture of self
}
}
}
var c: TimerClient? = TimerClient()
c!.start()
c = nil // no deinit — closure holds self strongly用捕获列表打破循环
使用 [weak self](可选)以便安全清理;只有在闭包执行时能保证 self 仍然存在,才使用 [unowned self]。
final class TimerClient2 {
var tick: (() -> Void)?
deinit { print("TimerClient2 deinit") }
func start() {
// Use [weak self] when self can go away before tick runs
tick = { [weak self] in
guard let self = self else { return } // safe unwrap
print("tick from", self)
}
// Alternative when lifetime is guaranteed: [unowned self]
// tick = { [unowned self] in print("tick from", self) }
}
}
var c2: TimerClient2? = TimerClient2()
c2!.start()
c2 = nil // deinit now prints — no cycle检查清单
检查清单:
- 存在双向引用?将其中一侧设为弱引用(例如委托)。
- 闭包被存储在某个类型中?捕获 [weak self] 并安全地解包。
- 只有在生命周期得到保证时才使用 [unowned self];否则可能导致崩溃。
闭包中的弱引用与无主引用
快速检查:当对象可能被释放时,哪一种捕获列表更安全?
回顾
回顾:识别对象和闭包中的循环。根据情况使用弱引用或无主引用打破循环;不确定时优先使用弱引用。
常见问题解答
「保留环及使用 weak/unowned 打破它们」课时是免费的吗?
是的 — 「保留环及使用 weak/unowned 打破它们」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Swift Academy 课程的其余内容,请升级到 CoddyKit PRO。 Swift Academy 课程共包含 3 节课。
「保留环及使用 weak/unowned 打破它们」这节课中我会学到什么?
识别对象与闭包之间的保留环,然后安全地使用 weak 和 unowned 引用打破它们。 你通过在浏览器中直接运行的动手代码来练习 Swift Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Swift Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Swift Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 3 节。
「保留环及使用 weak/unowned 打破它们」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Swift Academy 课中编写并运行代码吗?
能。每节 Swift Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- ARC 基础:strong / weak / unowned
- 保留环及使用 weak/unowned 打破它们
- 使用值类型减少共享