You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中A强引用B、B弱引用A时为何A总是比B先释放?

核心原因

你观察到的A实例永远先于B实例释放的现象,本质是强引用的持有逻辑导致的,B实例的生命周期完全被A实例的强引用绑定,只要A实例没有被销毁,B实例的引用计数就不可能降到0,自然不可能先于A触发deinit。

错误认知纠正

你认为bravo = nil会让alpha.b同步变为nil的认知是错误的:只有weak/unowned修饰的弱引用变量,才会在指向的实例被释放时自动置空;而A类的b属性是普通强引用,不会因为其他指向B实例的变量被置空就自动变为nil,它会一直持有B实例的强引用,直到A实例本身被销毁。

各阶段引用计数变化明细

初始状态

alpha、bravo均为nil,无实例存在。

执行setup函数阶段

  • 执行b = B():因为是inout参数,相当于给外部的bravo赋值B实例,此时B实例强引用计数=1,持有者为bravo
  • 执行a = A(b: b!):相当于给外部的alpha赋值A实例,A初始化时强持有传入的B实例,此时:
    • A实例强引用计数=1,持有者为alpha
    • B实例强引用计数+1 → 变为2,新增持有者为A实例的b属性
  • 执行b?.a = a:B的a属性是weak修饰的弱引用,赋值不会增加A的引用计数,两个实例的引用计数无变化
  • setup函数执行完毕,局部参数释放,不影响实例计数,此时持有关系为:
    alpha 强持有 → A实例 强持有 → B实例
    bravo 强持有 → B实例
    B实例 weak持有 → A实例
    

赋值nil阶段,两种顺序的表现一致

顺序1:先执行bravo = nil,再执行alpha = nil

  • bravo = nil:解除bravo对B实例的强引用,B的强引用计数-1 → 变为1,剩余A实例的b属性持有B,B不会释放
  • alpha = nil:解除alpha对A实例的强引用,A的强引用计数变为0,触发A的deinit,打印Destroying A;A被销毁后,它持有的b属性强引用也同步解除,B的强引用计数变为0,触发B的deinit,打印Destroying B

顺序2:先执行alpha = nil,再执行bravo = nil

  • alpha = nil:解除alpha对A实例的强引用,A的强引用计数变为0,触发A的deinit,打印Destroying A;A被销毁后,它持有的b属性强引用同步解除,B的强引用计数-1 → 变为1,剩余bravo持有B,B不会释放
  • bravo = nil:解除bravo对B实例的强引用,B的强引用计数变为0,触发B的deinit,打印Destroying B

两种顺序下都是A先释放、B后释放,和你测试的结果完全吻合。

内容的提问来源于stack exchange,提问作者theevo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 08:48:02