Swift闭包中deinit时机疑问:为何Increment实例提前销毁?
链式调用下Swift实例提前销毁的原因分析
下面两段Swift代码的执行结果存在明显差异:
链式调用写法
class Increment { var number = 0 init(){ print(#function) } deinit { print(#function) } // let incrementNumber would give an error — 1 lazy var incrementNumber: (Int) -> () = { [weak self] value in self?.number += value print(self?.number) } } do { let increment = Increment().incrementNumber(3) } // 输出: // init() // deinit // nil
拆分调用写法
当把代码拆分成以下形式时,闭包执行阶段self仍处于存活状态:
let increment = Increment() increment.incrementNumber(3) // 输出: // init() // Optional(3) // deinit
差异原因
链式调用Increment().incrementNumber(3)的执行逻辑是:
- 首先创建
Increment的临时实例,但这个实例没有被任何强引用变量持有; - 接着访问实例的
lazy属性incrementNumber,触发闭包初始化并获取到闭包对象; - 此时临时实例已经没有任何强引用,Swift的ARC(自动引用计数)会立刻销毁这个实例,调用
deinit; - 最后执行闭包时,
[weak self]已经变成nil,自然无法修改number,输出nil。
而拆分写法的逻辑是:
let increment = Increment()将实例赋值给变量increment,这个变量持有了实例的强引用;- 调用
increment.incrementNumber(3)时,实例仍被强引用持有,不会被销毁; - 闭包执行时
self有效,能正常修改number并输出Optional(3); - 只有当
increment超出作用域后,实例才会失去强引用,被销毁并调用deinit。
核心差异点在于链式调用中的临时实例没有被强引用持有,导致在闭包执行前就被ARC回收了。
内容的提问来源于stack exchange,提问作者alphabetF
相关产品推荐
相关产品推荐

