Что такое capture list (список захвата) в замыканиях Swift?

«Что такое capture list (список захвата) в замыканиях Swift?» — вопрос из категории Swift Core, который задают на 23% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Capture list (список захвата) — это синтаксическая конструкция в Swift, которая явно определяет, как замыкание захватывает переменные и константы из окружающего контекста. Её основная цель — управление памятью и предотвращение сильных циклов ссылок (retain cycles).

Базовый синтаксис: { [capture_specification] in ... }

Пример проблемы и решения:

class ViewController {
    var counter = 0
    var closure: (() -> Void)?

    func setupProblem() {
        // ПРОБЛЕМА: Сильный цикл! Замыкание сильно захватывает `self`,
        // а `self` сильно хранит замыкание в свойстве `closure`.
        closure = {
            self.counter += 1 // Сильный захват self
        }
    }

    func setupSolution() {
        // РЕШЕНИЕ: Используем capture list для слабого захвата.
        closure = { [weak self] in
            self?.counter += 1 // self теперь опциональный
        }
    }
}

Основные типы захвата в списке:

  • [weak object]: Захват слабой (weak) ссылки. Объект становится опциональным (T?) внутри замыкания. Используется для разрыва retain cycles.
  • [unowned object]: Захват безусловной (unowned) ссылки. Предполагает, что объект не будет освобожден. Опасен, если предположение неверно.
  • [variable = value]: Захват по значению (value capture). Фиксирует значение переменной на момент создания замыкания.
    var value = 10
    let closure = { [capturedValue = value] in
        print(capturedValue) // Всегда напечатает 10, даже если внешняя `value` изменится
    }
    value = 20
    closure() // Вывод: 10

Правило: Всегда используйте capture list ([weak self] или [unowned self]), когда замыкание, хранимое в свойстве класса, захватывает self.