Назад к вопросам
Middle
88
questionbank

Что вы знаете о capture list в Swift?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Capture list в Swift — это механизм, позволяющий явно указать, как замыкание захватывает одну или несколько переменных из окружающей области видимости. Он используется для разрешения проблем с retain cycles, особенно при захвате self.

Существует три типа захвата: weak, unowned и unowned(unsafe).

  1. weak: Захватывает переменную как опционал (Optional). Если объект, на который ссылается переменная, будет освобожден, переменная внутри замыкания станет nil. Используется для предотвращения retain cycles, когда одна ссылка может быть nil в течение жизненного цикла.

    // Пример с weak
    class ViewController {
        var dataTask: URLSessionDataTask?
    
        func loadData() {
            let url = URL(string: "...")!
            dataTask = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
                // self здесь опционал weakSelf
                guard let self = self else { return } // Распаковка weakSelf
                self.processData(data: data)
            }
            dataTask?.resume()
        }
    
        func processData(data: Data?) {
            // Обработка данных
        }
    }
    
  2. unowned: Захватывает переменную как неопознанную ссылку. Предполагается, что объект, на который ссылается переменная, имеет тот же или более длительный жизненный цикл, чем замыкание. Если объект освобождается до выполнения замыкания, попытка доступа к нему вызовет ошибку времени выполнения. Используется, когда одна ссылка гарантированно не nil в течение жизненного цикла.

    // Пример с unowned
    class Person {
        let name: String
        lazy var greeting: () -> String = { [unowned self] in
            return "Hello, I'm \(self.name)."
        }
    
        init(name: String) { self.name = name }
        deinit { print("\(name) is being deinitialized") }
    }
    
    var john: Person? = Person(name: "John")
    print(john!.greeting())
    john = nil // john.greeting() больше не должен быть вызван после этого
    
  3. unowned(unsafe): Подобно unowned, но не выполняет проверки времени выполнения. Использование не рекомендуется, если нет специфической необходимости в оптимизации и полной уверенности в жизненном цикле объекта.

Синтаксис capture list: [capture list]. Список помещается сразу после открывающей фигурной скобки замыкания.

// Общий синтаксис
{ [capturingValue1, capturingValue2] (parameters) -> returnType in
    // body of closure
}

Выбор между weak и unowned зависит от гарантированного жизненного цикла объектов. Если замыкание и захватываемый объект могут иметь разный жизненный цикл и объект может стать nil, используется weak. Если замыкаемый объект гарантированно существует, пока выполняется замыкание, используется unowned.