Всегда ли нужно использовать [weak self] в списке захвата замыкания в Swift?

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

Ответ

Нет, [weak self] требуется не для всех замыканий. Его необходимость определяется риском создания цикла сильных ссылок (retain cycle).

Используй [weak self] (или [unowned self]) когда:

  • Объект (self) хранит сильную ссылку на это замыкание (например, в своем свойстве).
  • Замыкание выполняется асинхронно или его вызов отложен во времени.
  • Жизненный цикл замыкания может превысить жизненный цикл self.

Пример цикла сильных ссылок:

class ViewController {
    var onDataLoaded: (() -> Void)? // Сильная ссылка на замыкание

    func setup() {
        onDataLoaded = {
            self.updateUI() // Замыкание сильно захватывает `self`
        }
        // `self` -> `onDataLoaded` -> `self` (ЦИКЛ!)
    }
}

Исправление с [weak self]:

func setup() {
    onDataLoaded = { [weak self] in
        self?.updateUI() // `self` теперь опциональная слабая ссылка
    }
}

Когда `[weak self] можно опустить:

  1. Замыкание с немедленным выполнением: Например, в методах высшего порядка map, filter, forEach, которые выполняются синхронно.
    let squares = numbers.map { $0 * $0 } // Нет риска цикла
  2. Замыкание не сохраняется: Когда замыкание передается как аргумент и не сохраняется объектом (например, completion-блок в UIView.animate).
  3. Гарантированный жизненный цикл: Когда время жизни self гарантированно больше времени жизни замыкания (редкий случай, часто [unowned self] подходит лучше, но требует осторожности).

Правило: Если есть сомнения — используй [weak self]. Это безопаснее, чем создание цикла или риск краша с unowned.