Closure escaping es un closure que "sale" del ámbito de la función que lo llama (por ejemplo, se guarda para su ejecución asíncrona).
Por defecto, en Swift, las funciones aceptan closures non-escaping: el closure se ejecuta dentro de la llamada a la función.
Para indicar explícitamente que es escaping se utiliza la palabra clave @escaping:
func asyncTask(completion: @escaping () -> Void) { DispatchQueue.main.async { completion() } }
Diferencias clave:
[weak self] o [unowned self] para evitar pérdidas de memoria (retain cycle).¿Es necesario siempre escribir @escaping para closures pasados como parámetros a la función que llama a DispatchQueue.async?
— Sí. Dado que DispatchQueue.async guarda el closure hasta el momento de su ejecución, el closure se convierte en escaping.
Ejemplo:
func foo(action: () -> Void) { DispatchQueue.main.async { action() // No se compilará: el closure debe ser escaping. } } // Necesario: func bar(action: @escaping () -> Void) { ... }
Historia
El controlador creó una referencia fuerte a self dentro de un closure escaping (por ejemplo, una solicitud de red). El controlador no se liberó después de salir de la pantalla — un ciclo de retención fuerte. Solución: usar [weak self] o [unowned self].
Historia
La función pasaba un closure a DispatchQueue.async, pero no lo marcó como escaping. El proyecto no se compilaba, y los errores eran difíciles de encontrar debido a la anidación de funciones.
Historia
Dentro del closure se hacía referencia a un objeto que ya había sido de-inicializado al momento de la llamada del closure (se usó [unowned self]). Como resultado: crash en tiempo de ejecución. Solución: usar [weak self] y verificar si es nil.