Objective-C сохранить цикл между 2 объектами

Вот код:

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

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

Я пытался установить ta = nil или же tb = nil, Не сработало но ta.b = nil работал. Зачем?

1 ответ

Решение

Я пытался установить ta = nil или же tb = nilэто не сработало,

Это потому, что, как вы указали, у вас есть "сильный референтный цикл" (ранее известный как "удерживающий цикл"). Это само определение сильного референтного цикла.

TestA возражать, что ta ссылка все еще имеет ссылку на TestB возражать, что tb изначально ссылка. Аналогично TestB возражать, что tb ссылка по-прежнему держит сильную ссылку на это TestA пример того, что ta изначально ссылка. Так что даже после того, как вы установите оба ta а также tb указатели на nilфактические объекты, на которые они первоначально указывали, все еще сохраняют ссылки друг на друга. Отсюда и цикл.

Ключевое наблюдение заключается в том, что когда вы устанавливаете ta а также tb указатели на nilничего не делает, кроме удаления ваших ссылок на эти TestA а также TestB экземпляров. Но пока что-то еще поддерживает строгую ссылку на эти экземпляры (в этом случае они поддерживают строгие ссылки друг на друга), они не будут освобождены. Мы называем память, связанную с этими двумя объектами, "заброшенной", т. Е. У вас нет ссылок на них, даже если они не освобождены, потому что они связаны друг с другом циклом сильных ссылок.

Функция "График отладочной памяти", действительно полезно для визуализации этого. Итак, после того, как я установил ta а также tb чтобы быть nilЯ посмотрел на график памяти, и он показывает, что мой ViewController больше не было ссылки на эти два объекта, но они все еще ссылаются друг на друга:

но ta.b = nil работал. Зачем??!!

Это работает (при условии, что вы сделали это до установки ta в nil), потому что это нарушает цикл сильных ссылок. Когда вы установите ta.b в nil, TestB У объекта больше нет сильных ссылок, и он может быть освобожден. И, как только это TestB экземпляр освобожден, он удалит ссылку на него TestA например, так что TestA экземпляр также будет освобожден, так как последняя сильная ссылка на него будет удалена.


Возможно, излишне говорить, но способ предотвратить эту проблему состоит в том, чтобы сделать одно из свойств weak, Например, если TestA является логическим "родительским" объектом, вы, вероятно, сделаете b недвижимость в TestA strong собственности, но сделать a недвижимость в TestB weak имущество. Это разрешает сильный референсный цикл и полностью устраняет эту проблему.

Другие вопросы по тегам