Как создать weak-замыкание в Swift для предотвращения цикла сильных ссылок?

«Как создать weak-замыкание в Swift для предотвращения цикла сильных ссылок?» — вопрос из категории Управление памятью, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Чтобы предотвратить retain cycle (цикл сильных ссылок) в замыкании, необходимо использовать список захвата для явного указания weak или unowned ссылок на захватываемые объекты.

1. Weak Capture ([weak self]): Рекомендуемый и безопасный подход. Делает захваченную ссылку опциональной.

class MyViewController: UIViewController {
    func setupHandler() {
        someAsyncTask { [weak self] in
            // self — опционален (WeakReference<Self>?)
            guard let strongSelf = self else {
                return // Объект был освобожден
            }
            strongSelf.updateUI()
            // Альтернативно: self?.updateUI()
        }
    }
}

2. Unowned Capture ([unowned self]): Используется, когда время жизни объекта гарантированно превышает время жизни замыкания. При обращении к освобожденному объекту вызовет краш.

class MySerializer {
    func serialize(completion: () -> Void) {
        // Гарантируется, что `self` существует при вызове completion
        performWork { [unowned self] in
            self.finalize() // Прямой доступ, не опционал
        }
    }
}
Ключевые различия: weak unowned
Тип ссылки Опциональная (T?) Неопциональная (T)
Поведение при dealloc Автоматически становится nil Остается висячей ссылкой (dangling)
Безопасность Безопасен, требует проверки Небезопасен, может привести к крашу
Использование Когда объект может быть освобожден Когда объект переживает замыкание

Правило: В большинстве асинхронных сценариев используйте [weak self]. [unowned self] применяйте только при абсолютной уверенности в жизненном цикле.