Что такое @escaping замыкание в Swift?

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

Ответ

@escaping — атрибут параметра-замыкания, указывающий, что замыкание может быть вызвано после возврата из функции. Требуется для асинхронных операций.

Пример с сетевым запросом:

func downloadData(from url: URL, 
                  completion: @escaping (Result<Data, Error>) -> Void) {
    URLSession.shared.dataTask(with: url) { data, _, error in
        // Замыкание выполняется асинхронно, после возврата из downloadData
        if let error = error {
            completion(.failure(error))
        } else if let data = data {
            completion(.success(data))
        }
    }.resume()
    // Функция завершается здесь, но completion ещё не вызван
}

Обязательное использование weak/unowned:

class DataLoader {
    var cachedData: Data?

    func loadData(completion: @escaping (Data) -> Void) {
        downloadData(from: someURL) { [weak self] result in
            guard let self = self else { return }

            switch result {
            case .success(let data):
                self.cachedData = data
                completion(data)
            case .failure(let error):
                print("Ошибка: (error)")
            }
        }
    }
}
Ключевые отличия: Не-escaping (по умолчанию) Escaping (@escaping)
Вызывается до возврата функции Может быть вызвано позже
Не требует захвата self Требует [weak self] для избежания retain cycle
Может быть mutating для value types Не может изменять value types
Оптимизируется компилятором Меньше оптимизаций