Вопрос проверяет знание одной из самых частых причин утечек памяти в iOS-приложениях.
Retain cycle возникает, когда два или более объекта удерживают друг друга сильными ссылками. В результате ARC не может освободить память. Чаще всего это происходит между view controller и замыканиями или делегатами. Для решения используют weak или unowned ссылки. Важно осознанно управлять владением объектами.
Retain cycle — это логическая ошибка владения, которую ARC не может исправить автоматически.
Retain cycle — ситуация, при которой объекты образуют замкнутую цепочку strong ссылок и никогда не освобождаются.
Самый частый кейс — замыкание, захватывающее self.
class ProfileViewModel {
var onUpdate: (() -> Void)?
func load() {
onUpdate = {
self.refresh()
}
}
func refresh() {}
}
Здесь:
ProfileViewModel сильно держит onUpdate.
Замыкание сильно держит self.
Объект никогда не освобождается.
Перед выбором решения важно понять, гарантирован ли жизненный цикл объекта.
Используется, когда объект может быть уничтожен.
onUpdate = { [weak self] in
self?.refresh()
}
Особенности:
Ссылка может стать nil.
Безопасна для UI и асинхронных операций.
Используется, если объект точно жив дольше замыкания.
onUpdate = { [unowned self] in
refresh()
}
Риск:
крэш при обращении к уничтоженному объекту.
Делегаты почти всегда объявляются как weak.
weak var delegate: SomeDelegate?
ViewController ↔ ViewModel.
ViewController ↔ Closure.
Parent ↔ Child.
Таймеры и NotificationCenter без отписки.
Instruments → Leaks / Allocations.
Логи в deinit.
Проверка жизненного цикла экранов.
Retain cycle — одна из главных причин утечек памяти. Осознанное использование weak и unowned, а также регулярная проверка deinit — обязательная практика в iOS-разработке.