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 = nil
或 tb = 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
实例的强引用。因此,即使在将 ta
和 tb
指针都设置为 nil
之后,它们最初指向的实际对象仍然保持相互引用。因此循环。
关键观察是,当您将 ta
和 tb
指针设置为 nil
时,除了删除您对这些 TestA
和TestB
个实例。但只要有其他东西保持对这些实例的强引用(在这种情况下,它们保持彼此的强引用),它们就不会被释放。我们将与这两个对象关联的内存称为已被“放弃”,即,即使它们未被释放,您也没有对它们的任何引用,因为它们被绑定在相互的强引用循环中。
"Debug Memory Graph" 特征,,在形象化方面非常有用。所以在我将 ta
和 tb
都设置为 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
属性。这解决了强引用循环并完全消除了这个问题。
代码如下:
TestA *ta = [[TestA alloc] init];
TestB *tb = [[TestB alloc] init];
ta.b = tb;
tb.a = ta;
我尝试设置 ta = nil
或 tb = nil
。它没有用,但 ta.b = nil
起作用了。为什么?
I tried to set
ta = nil
ortb = nil
, it didn't work,
这是因为,正如您所指出的,您有一个 "strong reference cycle"(以前称为 "retain cycle")。这正是强引用循环的定义。
ta
引用的 TestA
对象仍然引用 tb
最初引用的 TestB
对象。同样,tb
引用的 TestB
对象仍然保持对 ta
最初引用的那个 TestA
实例的强引用。因此,即使在将 ta
和 tb
指针都设置为 nil
之后,它们最初指向的实际对象仍然保持相互引用。因此循环。
关键观察是,当您将 ta
和 tb
指针设置为 nil
时,除了删除您对这些 TestA
和TestB
个实例。但只要有其他东西保持对这些实例的强引用(在这种情况下,它们保持彼此的强引用),它们就不会被释放。我们将与这两个对象关联的内存称为已被“放弃”,即,即使它们未被释放,您也没有对它们的任何引用,因为它们被绑定在相互的强引用循环中。
"Debug Memory Graph" 特征,ta
和 tb
都设置为 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
属性。这解决了强引用循环并完全消除了这个问题。