ProgrammazioneSviluppatore iOS

Descrivi il meccanismo di funzionamento di defer in Swift, con quali casi limite e caratteristiche bisogna prestare attenzione?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

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:

  • Se nella funzione ci sono più defer, verranno eseguiti in ordine inverso (struttura a pila LIFO - last in, first out).
  • defer viene eseguito anche in caso di errore (throw) o al momento di qualsiasi return dalla funzione.
  • Nel closure, defer è considerato come parte del corpo del closure e non del punto di chiamata del closure.

Esempio:

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

Casi limite:

  • defer acquisisce i valori delle variabili nel momento in cui viene dichiarato: se utilizziamo variabili in un defer closure, le modifiche a queste saranno visibili al momento dell'esecuzione del defer.
  • Se la funzione termina con fatalError, il defer non verrà chiamato.

Domanda insidiosa.

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

Esempi di veri errori dovuti alla mancanza di conoscenza delle sfumature dell'argomento.


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.