Зачем использовать [weak self] в замыканиях Swift?

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

Ответ

[weak self] используется для предотвращения цикла сильных ссылок (retain cycle).

Проблема: Если объект (например, контроллер) сильно захватывает (self) внутри замыкания, а это замыкание также сохраняется этим объектом, возникает взаимная блокировка в памяти. Оба объекта никогда не будут освобождены.

Решение: [weak self] создает слабую (weak) ссылку на self внутри замыкания, которая не увеличивает счетчик ссылок. Если self будет освобожден, ссылка станет nil.

Пример правильного использования:

class DataLoader {
    func loadData(completion: @escaping (Result<Data, Error>) -> Void) {
        URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
            // 1. Проверяем, "жив" ли еще self
            guard let self = self else { 
                print("Объект DataLoader был освобожден")
                return 
            }
            // 2. Используем self безопасно
            self.processData(data)
            completion(.success(data))
        }.resume()
    }
}

Альтернативы:

  • [unowned self] — используется, когда вы уверены, что self переживет замыкание. При обращении к освобожденному unowned self произойдет краш.
  • Правило: Используйте weak по умолчанию для асинхронных замыканий, unowned только при явной гарантии времени жизни.