Ответ
Ключевое слово weak используется в списке захвата замыкания для предотвращения цикла сильных ссылок (retain cycle).
Когда это необходимо?
Используйте [weak self], когда:
- Замыкание хранится как свойство (например, колбэк, обработчик).
selfвладеет этим замыканием (прямо или косвенно).- Замыкание может пережить
self(является@escaping).
Пример проблемы и решения:
class DataLoader {
var onComplete: (() -> Void)? // Хранимое escaping-замыкание
func loadData() {
// БЕЗ weak: ЦИКЛ! DataLoader владеет onComplete, а замыкание сильно ссылается на DataLoader.
// onComplete = { self.handleData() } // Память никогда не освободится.
// С weak: Цикл разорван.
onComplete = { [weak self] in
// self стал опциональным из-за weak
self?.handleData()
}
}
func handleData() { print("Data processed") }
deinit { print("DataLoader deallocated") }
}
Альтернатива unowned:
Используйте [unowned self], только если вы абсолютно уверены, что замыкание не переживет self. В противном случае это приведет к аварийному завершению.
// Допустимо, если замыкание выполняется синхронно в рамках жизни self.
dispatchQueue.async { [unowned self] in
self.updateUI() // Crash, если self к этому моменту освобожден!
}
Лучшая практика: По умолчанию используйте weak для @escaping замыканий и безопасно разворачивайте self с помощью guard:
onComplete = { [weak self] in
guard let self = self else { return }
self.handleData() // self теперь strong reference на время выполнения замыкания
}