ProgrammazioneSviluppatore iOS

Come funzionano gli inizializzatori failable (`init?`) in Swift? Quando e perché usarli, quali importanti sfumature bisogna considerare?

Supera i colloqui con l'assistente IA Hintsage

Risposta

Gli inizializzatori failable (init?) in Swift consentono di descrivere situazioni in cui la creazione di un'istanza di un tipo può fallire e restituire nil. Vengono spesso utilizzati per la convalida dei dati di input o per trasformazioni che potrebbero non avere successo. In un inizializzatore failable è possibile restituire esplicitamente nil, indicando una creazione dell'oggetto non riuscita.

Esempio:

struct User { let name: String let age: Int init?(name: String, age: Int) { guard !name.isEmpty, age > 0 else { return nil } self.name = name self.age = age } }

In questo modo si possono prevenire la creazione di oggetti non validi.

Importanti sfumature:

  • Nella catena di ereditarietà, gli inizializzatori failable possono essere sovrascritti solo da inizializzatori failable.
  • Quando si utilizza una struttura con un inizializzatore failable in un array, dove si sta mappando l'inizializzazione (compactMap), questo è comodo per filtrare istanze non valide.

Domanda trabocchetto

Domanda: Qual è la differenza tra init? e init! e quando utilizzare un inizializzatore failable con un unwrapping implicito?

Risposta: init? restituisce un opzionale (<type?>), e se l'inizializzazione fallisce, restituirà nil, richiedendo una gestione sicura. init! restituisce un opzionale non conquistato implicito (<type!>), e se l'inizializzazione fallisce, restituirà anch'esso nil, ma l'utilizzo di tale oggetto senza verifica porterà a un runtime-crash. Utilizzare init! solo se si è certi che l'inizializzazione non possa fallire nel proprio contesto (ad esempio, quando si lavora con storyboard in UIKit).

let value = Int("abc") // value sarà nil

Esempi di errori reali a causa della mancanza di conoscenza delle sfumature del tema.


Storia

Durante il parsing manuale di JSON è stato utilizzato un inizializzatore normale invece di uno failable. Questo ha portato alla creazione di "utenti vuoti", poiché la validazione non è stata eseguita e l'app non ha filtrato i dati non validi.


Storia

L'uso di init! con dati potenzialmente non validi ha portato al crash dell'app dopo un aggiornamento API: il formato dei dati di input è cambiato, e nel momento in cui si cercava di estrarre l'oggetto, si è verificata un'eccezione di runtime a causa del unwrapping implicito di nil.


Storia

Nella personalizzazione dell'implementazione failable init, è stato dimenticato di restituire esplicitamente nil per alcuni scenari, e alla fine la struttura è stata inizializzata con "campi sporchi", il che ha successivamente causato bug nella logica aziendale.