Ответ
Замыкания-параметры в Swift по умолчанию являются non-escaping. Это означает, что они должны быть выполнены до завершения работы функции и не могут быть сохранены для последующего использования.
Пометка @escaping требуется, когда замыкание должно "пережить" время выполнения функции. Это происходит в двух основных сценариях:
- Сохранение: Когда замыкание сохраняется в свойстве, глобальной переменной или любой другой структуре данных вне области видимости функции.
- Асинхронность: Когда замыкание передается в асинхронный вызов (например, в очередь
DispatchQueue), где оно будет выполнено позже.
Пример non-escaping замыкания:
func processItems(_ items: [Int], using handler: (Int) -> Void) {
for item in items {
handler(item) // Выполняется немедленно, внутри функции
}
// К этому моменту замыкание `handler` больше не существует
}
Пример escaping замыкания:
class DataManager {
var completionHandlers: [() -> Void] = []
func fetchData(completion: @escaping () -> Void) {
// 1. Сохраняем замыкание для вызова позже
completionHandlers.append(completion)
// 2. Или передаем в асинхронную задачу
DispatchQueue.global().async {
// Долгая операция...
DispatchQueue.main.async {
completion() // Вызывается после завершения `fetchData`
}
}
}
}
Ключевое отличие: Использование @escaping требует от разработчика явного управления захватом переменных (например, с помощью [weak self]), чтобы избежать цикла сильных ссылок, так как время жизни замыкания теперь неизвестно.