为什么Combine中被捕获的unowned self在实例销毁时不会触发运行时崩溃?
Combine未触发崩溃的原因说明
核心机制:订阅生命周期与自动取消逻辑
你观察到的现象本质和AnyCancellable的生命周期绑定规则直接相关:
- 你的订阅链路最终通过
store(in: &subscriptions)将生成的AnyCancellable实例存入了DetailsViewController的私有成员subscriptions集合中,这个集合的生命周期和VC完全绑定。 - 当VC在1秒后被dismiss销毁时,
subscriptions集合会随着VC的析构一起被释放,集合中存储的所有AnyCancellable实例在释放前会自动调用自身的cancel()方法,整个订阅管道会被直接终止,下游所有操作符的闭包都不会再接收任何事件。
具体执行时序
你的代码完整执行顺序如下:
- 0秒时发送22到subject,触发flatMap执行,此时self还存在,正常返回Future
- 1秒时VC被dismiss,引用计数归零触发deinit,
subscriptions释放,所有订阅被取消,控制台打印deinit - 5秒时Future的延迟回调触发,调用promise返回10,但此时订阅已经处于取消状态,Combine不会把这个事件向下游传递,后续的
map、sink闭包全程不会被执行,自然不会访问已经销毁的self,不会触发unowned的崩溃。
崩溃复现验证
如果想要验证这个逻辑,可以把存储订阅的subscriptions集合改成全局变量,不绑定到VC的生命周期:
// 全局存储,不会随VC销毁而释放 var globalSubscriptions = Set<AnyCancellable>()
然后把订阅的存储语句改成.store(in: &globalSubscriptions),此时VC销毁后订阅依然存在,5秒后Future的事件会继续向下游传递,调用map、sink里的闭包访问unowned self,就会触发你预期的崩溃。
内容的提问来源于stack exchange,提问作者MegaManX
相关产品推荐
相关产品推荐

