Escaping closure — это замыкание, которое "уходит" из области видимости вызывающей функции (например, сохраняется для асинхронного выполнения).
По умолчанию в Swift функции принимают не-escaping closure: замыкание выполняется в пределах вызова функции.
Для явного указания escaping используется ключевое слово @escaping:
func asyncTask(completion: @escaping () -> Void) { DispatchQueue.main.async { completion() } }
Ключевые отличия:
[weak self] или [unowned self] для предотвращения утечек памяти (retain cycle).Нужно ли всегда писать @escaping для замыканий, передаваемых в параметры функции, вызывающей DispatchQueue.async?
— Да. Так как DispatchQueue.async сохраняет closure до момента выполнения, closure становится escaping.
Пример:
func foo(action: () -> Void) { DispatchQueue.main.async { action() // Не скомпилируется: closure должен быть escaping. } } // Нужно: func bar(action: @escaping () -> Void) { ... }
История
Контроллер создал сильную ссылку на self внутри escaping closure (например, сетевой запрос). Контроллер не освобождался после ухода с экрана — сильный retain cycle. Решение: использовать [weak self] или [unowned self].
История
Функция передавала closure в DispatchQueue.async, но не пометила его как escaping. Проект не компилировался, ошибки было сложно найти из-за вложенности функций.
История
Внутри closure обращались к объекту, который уже деинициализировался к моменту вызова closure (использовали [unowned self]). В результате — runtime crash. Решение: использовать [weak self] и проверку на nil.