El operador defer retrasa la ejecución del código hasta que se sale del ámbito actual, generalmente de una función. Es útil para la limpieza de recursos, cierre de archivos y liberación de memoria — lo que se conoce como limpieza automatizada.
Características:
Ejemplo:
func processFile() { let file = openFile() defer { closeFile(file) } // Trabajo con el archivo // el archivo se cerrará incluso en caso de throw o return }
Uso atípico: imitación parcial de construcciones tipo 'finally', agrupación de código para registro y seguimiento de tiempos de ejecución.
¿Se ejecutará defer si la aplicación termina durante la ejecución de la función?
— No. Defer se ejecuta solo en la salida normal del ámbito (return, throw o salida normal). Si la aplicación termina abruptamente (por ejemplo, debido a una señal SIGKILL o fatalError), los bloques defer no tendrán tiempo de ejecutarse.
Ejemplo:
func foo() { defer { print("Limpiar") } fatalError("¡Error!") // defer no se ejecutará }
Historia
Una función que trabajaba con sockets no limpiaba la conexión en caso de throw. Los datos permanecían colgados, las conexiones no se liberaban. Después de introducir defer, todo funcionó correctamente: los recursos se cerraban siempre.
Historia
Un desarrollador intentó confiar en defer para liberar un estado global. Cuando ocurrió un fatalError, el recurso no se liberó, lo que provocó bloqueos en los servicios y la necesidad de reinicio.
Historia
En la función se declararon varios defer, pensando que se ejecutarían en el orden de declaración. Como resultado, los recursos se cerraban en un orden incorrecto (por ejemplo, primero se cerró el descriptor de archivo, y luego se intentó acceder a él). Solución: recordar el orden LIFO de ejecución de los bloques defer.