defer è una costruzione speciale di Swift che consente di eseguire un determinato blocco di codice immediatamente prima di uscire dallo scope della funzione, indipendentemente dal fatto che siamo usciti tramite un return normale o per errore (throw). È utile utilizzare defer per liberare risorse, annullare modifiche o finalizzare operazioni.
Caratteristiche di funzionamento:
Esempio:
func testDefer() { print("begin") defer { print("first defer") } defer { print("second defer") } print("end") } // Stampa: // begin // end // second defer // first defer
Casi limite:
Verranno eseguiti tutti i blocchi defer nella funzione se all'interno viene chiamato fatalError?
Risposta: No, se nella funzione viene chiamato fatalError (o crash incontrollati simili), tutti i blocchi defer non vengono eseguiti. defer non garantisce l'esecuzione del codice in caso di chiusure anomale dell'applicazione.
Esempio:
func foo() { defer { print("Defer 1") } fatalError("Oops") defer { print("Defer 2") } } foo() // non stampa nulla, si verifica un crash
Storia
Nel progetto si utilizzava defer per chiudere i descrittori di file. Quando si verificava un errore, si utilizzava fatalError invece di un corretto throw, il che portava a una perdita di risorsa aperta, poiché il defer non veniva eseguito in caso di crash.
Storia
In una funzione c'erano diversi defer, alcuni dei quali dipendevano dallo stato di variabili locali. Lo sviluppatore si aspettava che la variabile fosse uguale a un valore specifico, ma questo valore nel defer era cambiato da un altro pezzo di codice e durante l'esecuzione del defer veniva utilizzato il valore attuale, non quello precedente, portando a un bug nell'annullamento della transazione non per l'ID corretto.
Storia
In un closure annidato è stato scritto un blocco defer, pensando che sarebbe stato eseguito all'uscita dalla funzione esterna. Di conseguenza, questo defer è stato eseguito all'uscita dal closure, e non dall'intera funzione, e la risorsa è stata liberata troppo presto.