5-14.【OC】【Block】Swift 中 [weak self] 和 OC 中 __weak self 在生命周期管理上是否完全等价?

2 阅读3分钟

简单来说,它们在最终目的(打破循环引用)上是等价的,但在执行细节语法语义上,Swift 的 [weak self] 比 OC 的 __weak 走得更远,也更安全。

我们可以从以下三个维度来拆解它们的本质差异:


1. 定义时机与作用域 (Declaration vs. Capture List)

  • OC (__weak) 是“手动预处理”:

    在 OC 中,你必须在 Block 外部定义一个全新的局部变量(如 weakSelf)。Block 捕获的是这个新变量,而不是原始的 self。如果忘记写这行代码而在 Block 里直接用了 self,编译器通常只会给一个警告,循环引用依然会发生。

  • Swift ([weak self]) 是“捕获声明”:

    Swift 使用 Capture List(捕获列表) 。它直接在闭包的头部定义捕获规则。这意味着 self 在进入闭包那一刻,其捕获语义就被改变了。它不需要创建中间变量,语法上更加内聚。


2. 类型系统的安全性 (Optionality)

这是两者最显著的差异:

  • OC:指针透明性

    在 OC Block 内部,weakSelf 看起来和普通的 self 没区别。你可以直接调用方法:[weakSelf doSomething]。如果 self 已经释放,weakSelfnil,根据 OC 特性,向 nil 发消息什么都不会发生。

  • Swift:强制 Optional

    一旦在 Capture List 中声明了 weak self,在闭包内部 self 的类型就从 Self 变成了 Self?(Optional) 。编译器会强制你处理 nil 的情况(使用 guard letself?)。这种“类型降级”在编译阶段就逼你考虑对象提前释放的可能性。


3. “强引用提升”的实现方案 (Strong-Weak Dance)

为了防止代码执行到一半 self 突然消失,我们通常需要临时把弱引用变回强引用。

Objective-C 方案:

需要手动再次定义一个 __strong 变量:

Objective-C

__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;

Swift 方案:

Swift 提供了更优雅的语法糖。在早期的 guard let self = self 之后,Swift 5.7+ 允许你直接写:

Swift

guard let self = self else { return }
// 此后 self 在闭包作用域内变回了强引用的非可选类型

本质差异: Swift 的这种“重新绑定”受语言编译器保护,确保了在闭包执行期间,self 的生命周期会被临时延长,直到闭包结束。


4. 性能上的细微差别

  • OC: 依赖于 Runtime 的全局弱引用表(SideTable)。每次 weakSelf 的读写都涉及一次查表和可能的加锁操作。
  • Swift: 虽然同样依赖类似的弱引用计数机制,但 Swift 的内存管理(引用计数存储在对象头部的 inline 空间或外部的 SideTable 中)与编译器高度优化。由于 Swift 闭包捕获列表在编译期就确定了布局,在某些情况下,编译器能比 OC 产生更高效的寻址代码。

总结对照表

特性Objective-C __weakSwift [weak self]
位置闭包外部手动创建闭包头部的捕获列表
类型原始类型指针 (可赋 nil)Optional 类型 (Self?)
编译器检查弱(容易漏写导致强引用)强(强制处理可选值)
空处理向 nil 发消息 (无操作)必须通过 Optional Binding 处理