Swift supporta un sistema rigoroso di gestione degli errori tramite il protocollo Error e le istruzioni throw, try, catch. Puoi definire i tuoi tipi di errore ereditando da Error:
enum NetworkError: Error { case noInternet case serverError(code: Int) case unknown }
Le funzioni che possono lanciare un errore vengono dichiarate con throws:
func fetchData() throws -> Data { // ... throw NetworkError.noInternet }
Gli errori possono essere gestiti utilizzando un blocco do-catch:
do { let data = try fetchData() // Elaborazione dei dati } catch NetworkError.noInternet { print("Nessuna connessione internet") } catch { print("Altro errore: \(error)") }
Un approccio alternativo è il tipo Result<T, Error>, che consente di restituire un risultato o un errore senza necessità di try-catch:
func fetchData() -> Result<Data, NetworkError> { // ... return .failure(.noInternet) } let result = fetchData() switch result { case .success(let data): // OK case .failure(let err): // Gestione dell'errore }
Quando utilizzare:
try/catch se l'errore è critico e non può essere ignorato.Result se la funzione è asincrona o quando è comodo passare l'errore "all'esterno" senza eccezioni.Domanda: "È possibile lanciare e catturare errori di qualsiasi tipo, ad esempio stringhe o numeri?"
Risposta: No, in Swift è possibile lanciare solo tipi che implementano il protocollo Error.
// Sbagliato: throw "StringError" // Il compilatore non lo permetterà // Giusto: struct MyError: Error {} throw MyError()
Storia
Nel progetto REST API, il client lanciava un errore come stringa (throw "No data"). Il codice compilava in JavaScript, ma dopo la conversione in Swift si è verificato un errore di compilazione fatale.
Storia
Uno sviluppatore restituiva errori tramite valori opzionali (return nil in caso di errore) invece di usare throw/Result. Di conseguenza, i dettagli degli errori sono andati persi, ed è stato difficile gestirli correttamente - si sono verificati Silent fails.
Storia
L'analisi ha mostrato che in diverse parti dell'app le stesse errori non erano state raggruppate in un unico tipo di Error. Di conseguenza, le applicazioni trattavano in modo diverso gli stessi fallimenti, l'interfaccia utente mostrava messaggi diversi per lo stesso errore - difficile da mantenere e testare.