以下是代码:
TestA *ta = [[TestA alloc] init];
TestB *tb = [[TestB alloc] init];
ta.b = tb;
tb.a = ta;
我尝试设置ta = nil
或tb = nil
。它没有用,但ta.b = nil
有效。为什么呢?
答案 0 :(得分:3)
我尝试设置
ta = nil
或tb = nil
,但它没有用,
这是因为,正如您所指出的,您有一个强大的参考周期" (以前称为"保留周期")。这是强参考周期的定义。
TestA
引用的ta
对象仍然引用TestB
最初引用的tb
对象。同样,TestB
引用的tb
对象仍然保留对TestA
最初引用的ta
实例的强引用。因此,即使将ta
和tb
指针都设置为nil
,它们最初指向的实际对象仍然保持对彼此的引用。因此循环。
关键的一点是,当您将ta
和tb
指针设置为nil
时,除了删除对这些TestA
和{{{{}}的引用之外,它不会执行任何操作1}}实例。但只要有其他东西保持对这些实例的强烈引用(在这种情况下,他们“保持对彼此的强引用),他们就不会被解除分配。我们将与这两个对象相关联的内存称为“被抛弃”,即,即使它们未被释放,您也没有任何对它们的引用,因为它们在相互较强的引用周期中被捆绑在一起。
"调试内存图"功能,在可视化中非常有用。因此,在我将TestB
和ta
设置为tb
之后,我查看了内存图,它显示我的nil
不再引用这两个对象,但是他们仍然互相引用:
但
ViewController
有效。为什么?? !!
这可行(假设您在将ta.b = nil
设置为ta
之前执行此操作),因为它会破坏强引用周期。当您将nil
设置为ta.b
时,nil
对象不再具有任何强引用,并且可以将其取消分配。并且,一旦该TestB
实例被释放,它将删除对该TestB
实例的引用,以便TestA
实例也将被释放,因为它的最后一个强引用将被删除
也许不用说,但是你防止这个问题的方法是制作一个属性TestA
。例如,如果weak
是逻辑“父”对象,则您可能会在TestA
b
属性中生成TestA
属性,但请生成strong
} a
TestB
属性中的属性。这解决了强大的参考周期并完全消除了这个问题。