0Pricing
Swift Academy · 课时

保留环及使用 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 反馈 — 无需本地设置。

此课程中的所有课时

  1. ARC 基础:strong / weak / unowned
  2. 保留环及使用 weak/unowned 打破它们
  3. 使用值类型减少共享
← 返回 Swift Academy