ProgramaciónDesarrollador iOS

Describe el mecanismo de trabajo de defer en Swift, ¿con qué casos límite y características deben tener cuidado?

Supere entrevistas con el asistente de IA Hintsage

Respuesta.

defer es una construcción especial de Swift que permite ejecutar un bloque específico de código justo antes de salir del ámbito (scope) de una función, independientemente de si salimos por un return normal o por un error (throw). Defer es útil para liberar recursos, deshacer cambios o finalizar operaciones.

Características del funcionamiento:

  • Si hay varios defer en una función, se ejecutarán en orden inverso (estructura de pila LIFO — last in, first out).
  • defer se ejecuta incluso si ocurre un error (throw) o cualquier return de la función.
  • Dentro de un closure, defer se vincula al cuerpo del closure, no al lugar de llamada del closure.

Ejemplo:

func testDefer() { print("begin") defer { print("first defer") } defer { print("second defer") } print("end") } // Imprimirá: // begin // end // second defer // first defer

Casos límite:

  • defer captura los valores de las variables en el momento de su aparición: si en el closure defer usamos variables, los cambios en ellas serán visibles en el momento de la ejecución de defer.
  • Si la función finaliza con fatalError — defer no se llamará.

Pregunta trampa.

¿Se ejecutarán todos los bloques defer en la función si se llama fatalError dentro de ella?

Respuesta: No, si en la función se llama a fatalError (o errores no controlados similares), todos los bloques defer no se ejecutan. defer no garantiza la ejecución de código en casos de finalización abrupta de la aplicación.

Ejemplo:

func foo() { defer { print("Defer 1") } fatalError("Oops") defer { print("Defer 2") } } foo() // no imprimirá nada, resultará en un crash

Ejemplos de errores reales debido al desconocimiento de los matices del tema.


Historia

En el proyecto se utilizó defer para cerrar el descriptor de archivo. Al aparecer un error, se usó fatalError en lugar de un throw correcto, lo que llevó a una fuga de recurso abierto, ya que defer no se ejecutó en caso de crash.


Historia

En una función había varios defer, algunos de los cuales dependían del estado de las variables locales. El desarrollador esperaba que la variable tuviera un valor específico, pero este valor en defer fue modificado por otro fragmento de código, y al ejecutar defer se utilizó el valor actual, y no el antiguo, lo que llevó a un error en la cancelación de la transacción por el ID incorrecto.


Historia

Dentro de un closure, se escribió un bloque defer, pensando que se ejecutaría al salir de la función externa. Como resultado, este defer se ejecutó al salir del closure, y no de toda la función, y el recurso se liberó demasiado pronto.