Objective-C 2个对象之间的保留循环

Objective-C retain cycle between 2 objects

代码如下:

TestA *ta = [[TestA alloc] init];
TestB *tb = [[TestB alloc] init];  

ta.b = tb;
tb.a = ta;

我尝试设置 ta = niltb = nil。它没有用,但 ta.b = nil 起作用了。为什么?

I tried to set ta = nil or tb = nil, it didn't work,

这是因为,正如您所指出的,您有一个 "strong reference cycle"(以前称为 "retain cycle")。这正是强引用循环的定义。

ta 引用的 TestA 对象仍然引用 tb 最初引用的 TestB 对象。同样,tb 引用的 TestB 对象仍然保持对 ta 最初引用的那个 TestA 实例的强引用。因此,即使在将 tatb 指针都设置为 nil 之后,它们最初指向的实际对象仍然保持相互引用。因此循环。

关键观察是,当您将 tatb 指针设置为 nil 时,除了删除您对这些 TestATestB 个实例。但只要有其他东西保持对这些实例的强引用(在这种情况下,它们保持彼此的强引用),它们就不会被释放。我们将与这两个对象关联的内存称为已被“放弃”,即,即使它们未被释放,您也没有对它们的任何引用,因为它们被绑定在相互的强引用循环中。

"Debug Memory Graph" 特征,,在形象化方面非常有用。所以在我将 tatb 都设置为 nil 之后,我查看了内存图,它显示我的 ViewController 不再引用这两个对象,但是他们仍然互相引用:

but ta.b = nil worked. why??!!

这行得通(假设您在将 ta 设置为 nil 之前这样做了)因为它打破了强引用循环。当您将 ta.b 设置为 nil 时,TestB 对象不再具有任何强引用,它可以被释放。并且,一旦 TestB 实例被释放,它将删除它对 TestA 实例的引用,因此 TestA 实例也将被释放,因为对它的最后一个强引用将被删除.


也许不用说,但是防止此问题的方法是使其中一个属性weak。例如,如果 TestA 是逻辑上的“父”对象,您可能会将 TestA 中的 b 属性 设为 strong 属性 , 但将 TestB 中的 a 属性 设为 weak 属性。这解决了强引用循环并完全消除了这个问题。