Что такое capture list в замыканиях Swift и зачем она нужна?

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

Ответ

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

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

class MyViewController {
    var closure: (() -> Void)?

    func problematicSetup() {
        closure = { 
            self.doSomething() // Сильный захват `self` -> ЦИКЛ!
        }
    }
    // `self` удерживает `closure`, а `closure` удерживает `self`.
}

Решение с использованием capture list:

func correctSetup() {
    // [weak self] создает слабую (optional) ссылку
    closure = { [weak self] in
        self?.doSomething() // `self` стал Optional
    }

    // [unowned self] создает unowned (non-optional, но небезопасную) ссылку
    closure = { [unowned self] in
        self.doSomething() // Краш, если `self` освобожден
    }
}

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

  • Используйте [weak capturedInstance], если захваченный объект может стать nil (наиболее безопасный и распространенный способ).
  • Используйте [unowned capturedInstance], только если время жизни объекта гарантированно превышает время жизни замыкания (редкие случаи, риск краша).
  • Можно захватывать значения по значению: [x, y] — создается локальная копия.
  • Можно давать новые имена: [weak weakSelf = self].

Пример с несколькими захватами:

networkService.fetchData { [weak self, unowned database, count = totalAttempts] result in
    guard let self = self else { return }
    self.handle(result, from: database)
    print("Attempt: (count)")
}

Зачем это нужно: Без правильного capture list замыкания, захватывающие self или другие ссылочные типы, могут создавать циклы удержания памяти, приводящие к утечкам.