这是代码:
TestA *ta = [[TestA alloc] init];
TestB *tb = [[TestB alloc] init];
ta.b = tb;
tb.a = ta;
我试图设置ta = nil
或tb = nil
。它没有用,但ta.b = nil
有效。为什么?
这是代码:
TestA *ta = [[TestA alloc] init];
TestB *tb = [[TestB alloc] init];
ta.b = tb;
tb.a = ta;
我试图设置ta = nil
或tb = nil
。它没有用,但ta.b = nil
有效。为什么?
我试图设置
ta = nil
或tb = nil
,它没有工作,
这是因为,正如您所指出的,您有一个“强参考周期”(以前称为“保留周期”)。这就是强参考循环的定义。
引用的TestA
对象ta
仍然具有对最初引用的TestB
对象的tb
引用。同样,引用的TestB
对象tb
仍然保持对最初引用的那个TestA
实例的强ta
引用。因此,即使您将ta
和tb
指针都设置为nil
,它们最初指向的实际对象仍然保持对彼此的引用。因此循环。
关键的观察是,当您设置ta
和tb
指向 时,除了删除对这些和实例nil
的引用之外,它不会做任何事情。但是只要有其他东西保持对这些实例的强引用(在这种情况下,它们保持对彼此的强引用),它们就不会被释放。我们将与这两个对象关联的内存称为“已被放弃”,即,即使它们没有被释放,您也没有对它们的任何引用,因为它们被绑定在相互强引用循环中。TestA
TestB
“调试内存图”功能在可视化这方面非常有用。所以在我设置
ta
and tb
to both be之后nil
,我查看了内存图,它表明我ViewController
不再引用这两个对象,但它们仍然相互引用:
但
ta.b = nil
工作。为什么??!!
这有效(假设您在设置ta
为之前执行此操作nil
),因为它打破了强引用循环。当您设置ta.b
为nil
时,TestB
对象不再有任何强引用并且可以被释放。并且,一旦该TestB
实例被释放,它将删除对该TestA
实例的引用,因此该TestA
实例也将被释放,因为对它的最后一个强引用将被删除。
或许不用说,但您防止此问题的方法是创建属性之一weak
。例如,如果TestA
是逻辑“父”对象,您可能会在b
属性中TestA
创建strong
属性,但在a
属性中TestB
创建weak
属性。这解决了强引用循环并完全消除了这个问题。