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

Objective-C中两对象循环引用:为何直接置nil无效,置属性为nil有效?

为什么置空变量无法打破OC循环引用,但置空属性可以?

这个问题其实戳中了Objective-C强引用循环的核心——引用计数的变化到底发生在谁身上,咱们一步步拆解来看就清楚了:

先搞懂初始状态的引用关系

假设TestA的b属性和TestB的a属性都是强引用属性(这是循环引用的前提),咱们逐个看代码执行后的引用计数变化:

  • TestA *ta = [[TestA alloc] init];:TestA对象被创建,引用计数为1,同时变量ta作为强指针,牢牢“抓着”这个TestA对象(计数保持1)。
  • TestB *tb = [[TestB alloc] init];:同理,TestB对象引用计数为1,变量tb抓着它。
  • ta.b = tb;:TestA对象的b属性会再“抓”一次TestB,TestB的引用计数变成2(变量tb + TestA的b属性)。
  • tb.a = ta;:TestB对象的a属性再“抓”一次TestA,TestA的引用计数变成2(变量ta + TestB的a属性)。

这时候两个对象形成了死循环:TestA被TestB抓着,TestB被TestA抓着,同时各自还被变量ta/tb抓着,谁也没法被销毁。

为什么ta = nil或tb = nil没用?

当你执行ta = nil,只是变量ta松开了对TestA对象的抓握——TestA的引用计数从2降到1,但TestB对象的a属性还死死抓着TestA呢!
同时,TestA对象还活着,它的b属性还抓着TestB,所以TestB的引用计数还是2(变量tb + TestA的b),根本降不到0。
同理,tb = nil也只是变量tb松开TestB,TestB计数从2到1,但TestA的b还抓着它,TestA的计数也还是2,两个对象都不会被释放,循环依然存在。

为什么ta.b = nil就有效?

当你执行ta.b = nil,是让TestA对象的b属性松开对TestB的抓握——TestB的引用计数直接从2降到1,现在只有变量tb还抓着TestB了。
接下来只要做这两步:

  1. ta = nil:变量ta松开TestA,TestA的引用计数从2降到1(只剩TestB的a属性抓着它);
  2. tb = nil:变量tb松开TestB,TestB的引用计数降到0,TestB会被系统销毁。

关键来了:TestB被销毁的时候,它的所有属性都会被自动置nil(包括强属性a),这就相当于TestB的a属性也松开了对TestA的抓握,TestA的引用计数从1降到0,TestA也跟着被销毁——循环彻底被打破!

一句话总结

ta = nil只是解除了外部变量对对象的强引用,但对象内部的互相引用还在;而ta.b = nil是直接切断了对象之间的互相强引用链,让后续的变量释放能触发整个循环的销毁流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:24:57