Historia de la cuestión:
defer fue introducido en Swift para gestionar más convenientemente los recursos y llevar a cabo operaciones después de que se complete un bloque de código, similar a finally en otros lenguajes. Esta construcción ayuda a mostrar explícitamente las etapas de limpieza o finalización del trabajo con los recursos.
Problema:
Muchos principiantes creen que defer ejecuta inmediatamente el código anidado, sin entender siempre el momento en que se activa. También hay situaciones en las que varios bloques defer son difíciles de entender si no se conoce la regla LIFO (last-in, first-out). Pueden surgir dificultades con try/catch y salidas anticipadas.
Solución:
defer ejecuta el código anidado al final del scope, antes de salir del bloque de la función actual, incluso si la salida de la función ocurre antes (a través de return, throw, break, etc.). Varios defer se ejecutan en orden inverso a su aparición.
Ejemplo de código:
func readFile() { print("Abrir archivo") defer { print("Cerrar archivo") } print("Leer línea 1") if Bool.random() { print("Salida anticipada!") return } print("Leer línea 2") } readFile() // En la consola siempre se mostrará: Abrir archivo, ..., Cerrar archivo (al final)
Características clave:
¿Se puede usar defer fuera de una función?
No, defer está permitido solo dentro de funciones, métodos, inicializadores y desinicializadores. No se puede colocar, por ejemplo, en el espacio de nombres global del archivo o dentro de un bloque de código fuera de las funciones.
¿Qué ocurrirá con defer si hay una excepción (throw) en el bloque?
defer se ejecutará de todos modos. Esta es una de sus ventajas: el recurso se libera garantizadamente incluso en caso de error (throw). Así se implementa el patrón de liberación segura de recursos.
¿En qué orden se ejecutan varios defer?
Se ejecutan en orden inverso (LIFO): el defer que se declaró más tarde se ejecutará primero.
Ejemplo de código:
func test() { defer { print("Primero") } defer { print("Segundo") } print("Dentro") } test() // Salida: "Dentro", "Segundo", "Primero"
Función con varios defer, dispuestos de manera no secuencial; se olvidaron de limpiar algunos recursos, regresando de la función en diferentes lugares. Esto conduce a fugas de recursos y a una depuración del comportamiento difícil.
Ventajas: Uniformidad del código, acciones de limpieza "reunidas" en un solo lugar.
Desventajas: Difícil de seguir qué se ejecutará y en qué orden; posibles fugas debido a errores en la lógica.
Se hace un defer para cada etapa importante, colocado justo donde el recurso es inicializado, con comentarios. Se revisa el código.
Ventajas: Limpieza garantizada de los recursos, comprensión clara del orden de las acciones.
Desventajas: Requiere disciplina y atención al agregar nuevos recursos y bloques de limpieza.