L'operatore defer ritarda l'esecuzione del codice fino all'uscita dal contesto attuale, di solito da una funzione. È utile per la pulizia delle risorse, la chiusura dei file e il rilascio della memoria, noto come cleanup automatizzato.
Caratteristiche:
Esempio:
func processFile() { let file = openFile() defer { closeFile(file) } // Lavoro con il file // il file sarà chiuso anche in caso di throw o return }
Uso atipico: imitazione parziale delle costruzioni tipo 'finally', raggruppamento di codice per registrazione e monitoraggio dei tempi di esecuzione.
Il defer verrà eseguito se l'applicazione termina durante l'esecuzione della funzione?
— No. Defer viene eseguito solo in caso di uscita normale dal contesto (return, throw o uscita normale). Se l'applicazione termina in modo anomalo (ad esempio, a causa di un segnale SIGKILL o fatalError), i blocchi defer non verranno eseguiti.
Esempio:
func foo() { defer { print("Pulizia") } fatalError("Crash!") // defer non verrà eseguito }
Storia
Una funzione che lavorava con i socket non puliva la connessione in caso di throw. I dati rimanevano bloccati, le connessioni non venivano liberate. Dopo aver inserito defer, tutto ha funzionato correttamente: le risorse venivano sempre chiuse.
Storia
Uno sviluppatore cercava di fare affidamento su defer per liberare uno stato globale. In caso di fatalError, le risorse non venivano liberate, causando blocchi nei servizi e necessità di riavvio.
Storia
Nella funzione sono stati dichiarati più defer, pensando che sarebbero stati eseguiti nell'ordine di dichiarazione. Di conseguenza, le risorse venivano chiuse nell'ordine errato (ad esempio, prima si chiudeva il file descriptor e poi si cercava di accedervi). Soluzione: ricordare l'ordine LIFO nell'esecuzione dei blocchi defer.