Middle
63
questionbank

Что такое циклы удержания (retain cycles) в iOS?

Получайте ответы на вопросы в реальном времени с Sobes Copilot
Ответ от нейросети sobes.tech

Циклы удержания возникают, когда два или более объекта имеют сильные ссылки друг на друга, создавая "замкнутый круг". Вследствие этого, счетчик ссылок каждого объекта никогда не достигает нуля, и он не может быть освобожден ARC (Automatic Reference Counting). Это приводит к утечкам памяти, так как объекты остаются в памяти даже после того, как они перестают использоваться.

Пример:

swift

В этом примере, если Person имеет сильную ссылку на Apartment, а Apartment имеет сильную ссылку на Person, то при попытке освободить эти объекты они не будут удалены, так как их счетчики ссылок не достигнут нуля.

Как решить проблему циклов удержания:

Используйте слабые (weak) или бесхозные (unowned) ссылки.

  • weak: Используется, когда возможно, что связанный объект станет nil в течение жизненного цикла другого объекта. Ссылка становится nil автоматически, когда объект, на который она ссылается, освобождается. Является опционалом.
  • unowned: Используется, когда известно, что связанный объект имеет тот же или более длительный жизненный цикл, чем объект, имеющий на него ссылку. Не может быть nil.

Исправленный пример с использованием weak:

Изменим ссылку tenant в классе Apartment на слабую:

swift

Теперь, когда Person объект освобождается, ссылка tenant в Apartment автоматически становится nil, разрывая цикл удержания и позволяя Apartment также быть освобожденным.

Таблица сравнения weak и unowned:

Характеристикаweakunowned
Тип ссылкиОпциональныйНеопциональный
Может быть nil?Да, при освобождении объектаНет
Когда использоватьКогда объект может быть nilКогда объект не может быть nil
ПроизводительностьНемного медленнее из-за проверки на nilСлегка быстрее

Также циклы удержания могут возникать в замыканиях.

Когда замыкание захватывает instance properties или self, оно может создать сильную ссылку на объект. Если этот объект также имеет сильную ссылку на замыкание (например, через свойство-замыкание или делегата), возникает цикл удержания.

Как решить проблему циклов удержания в замыканиях:

Используйте список захвата (capture list).

swift

В данном примере [weak self] создает слабую ссылку на self внутри замыкания, предотвращая цикл удержания.