-1

这是代码:

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

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

我试图设置ta = niltb = nil。它没有用,但ta.b = nil有效。为什么?

4

1 回答 1

2

我试图设置ta = niltb = nil,它没有工作,

这是因为,正如您所指出的,您有一个“强参考周期”(以前称为“保留周期”)。这就是强参考循环的定义。

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

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

“调试内存图”功能在此处输入图像描述在可视化这方面非常有用。所以在我设置taand tbto both be之后nil,我查看了内存图,它表明我ViewController不再引用这两个对象,但它们仍然相互引用:

在此处输入图像描述

ta.b = nil工作。为什么??!!

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


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

于 2018-03-31T04:47:39.800 回答