Зачем в Swift использовать capture list в замыканиях?

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

Ответ

Capture list (список захвата) явно определяет, как замыкание захватывает переменные из окружающего контекста. Без него захват происходит по сильной ссылке (strong) по умолчанию, что может привести к retain cycle (циклу сильных ссылок) и утечке памяти.

Проблема (retain cycle):

class ViewController {
    var onAction: (() -> Void)?

    func setup() {
        // Захват self по сильной ссылке -> ЦИКЛ!
        onAction = {
            self.doSomething() // self удерживает onAction, onAction удерживает self
        }
    }
}

Решение с capture list:

func setup() {
    // [weak self] делает ссылку слабой (weak)
    onAction = { [weak self] in
        self?.doSomething() // self стал Optional
    }
    // [unowned self] делает ссылку бесхозной (unowned) – используйте осторожно!
    onAction = { [unowned self] in
        self.doSomething() // Краш, если self будет освобожден
    }
}

Ключевые правила:

  1. Используйте [weak] для захвата опциональных ссылок, которые могут стать nil.
  2. Используйте [unowned] только если захваченный объект гарантированно переживет замыкание.
  3. Также можно захватывать и копировать значения: [x, y] или [someValue = self.value].