Swift Language
Gestione degli errori
Ricerca…
Osservazioni
Per ulteriori informazioni sugli errori, vedere The Swift Programming Language .
Errore nella gestione delle basi
Le funzioni in Swift possono restituire valori, generare errori o entrambi:
func reticulateSplines() // no return value and no error
func reticulateSplines() -> Int // always returns a value
func reticulateSplines() throws // no return value, but may throw an error
func reticulateSplines() throws -> Int // may either return a value or throw an error
Qualsiasi valore conforme al protocollo ErrorType (inclusi gli oggetti NSError) può essere generato come un errore. Le enumerazioni forniscono un modo conveniente per definire errori personalizzati:
enum NetworkError: ErrorType {
case Offline
case ServerError(String)
}
enum NetworkError: Error {
// Swift 3 dictates that enum cases should be `lowerCamelCase`
case offline
case serverError(String)
}
Un errore indica un errore non irreversibile durante l'esecuzione del programma ed è gestito con i costrutti di flusso di controllo specializzati che do
/ catch
, throw
e try
.
func fetchResource(resource: NSURL) throws -> String {
if let (statusCode, responseString) = /* ...from elsewhere...*/ {
if case 500..<600 = statusCode {
throw NetworkError.serverError(responseString)
} else {
return responseString
}
} else {
throw NetworkError.offline
}
}
Gli errori possono essere catturati con do
/ catch
:
do {
let response = try fetchResource(resURL)
// If fetchResource() didn't throw an error, execution continues here:
print("Got response: \(response)")
...
} catch {
// If an error is thrown, we can handle it here.
print("Whoops, couldn't fetch resource: \(error)")
}
Qualsiasi funzione che può generare un errore deve essere chiamata usando try
, try?
, o try!
:
// error: call can throw but is not marked with 'try'
let response = fetchResource(resURL)
// "try" works within do/catch, or within another throwing function:
do {
let response = try fetchResource(resURL)
} catch {
// Handle the error
}
func foo() throws {
// If an error is thrown, continue passing it up to the caller.
let response = try fetchResource(resURL)
}
// "try?" wraps the function's return value in an Optional (nil if an error was thrown).
if let response = try? fetchResource(resURL) {
// no error was thrown
}
// "try!" crashes the program at runtime if an error occurs.
let response = try! fetchResource(resURL)
Cattura diversi tipi di errore
Creiamo il nostro tipo di errore per questo esempio.
enum CustomError: ErrorType {
case SomeError
case AnotherError
}
func throwing() throws {
throw CustomError.SomeError
}
enum CustomError: Error {
case someError
case anotherError
}
func throwing() throws {
throw CustomError.someError
}
La sintassi Do-Catch consente di rilevare un errore generato e crea automaticamente un error
denominato costante disponibile nel blocco catch
:
do {
try throwing()
} catch {
print(error)
}
Puoi anche dichiarare una variabile tu stesso:
do {
try throwing()
} catch let oops {
print(oops)
}
È anche possibile collegare diverse dichiarazioni di catch
. Questo è utile se possono essere lanciati diversi tipi di errori nel blocco Do.
Qui Do-Catch tenterà prima di lanciare l'errore come CustomError
, quindi come NSError
se il tipo personalizzato non è stato abbinato.
do {
try somethingMayThrow()
} catch let custom as CustomError {
print(custom)
} catch let error as NSError {
print(error)
}
In Swift 3, non c'è bisogno di downcast esplicitamente a NSError.
do {
try somethingMayThrow()
} catch let custom as CustomError {
print(custom)
} catch {
print(error)
}
Catch and Switch Pattern for Explicit Error Handling
class Plane {
enum Emergency: ErrorType {
case NoFuel
case EngineFailure(reason: String)
case DamagedWing
}
var fuelInKilograms: Int
//... init and other methods not shown
func fly() throws {
// ...
if fuelInKilograms <= 0 {
// uh oh...
throw Emergency.NoFuel
}
}
}
Nella classe cliente:
let airforceOne = Plane()
do {
try airforceOne.fly()
} catch let emergency as Plane.Emergency {
switch emergency {
case .NoFuel:
// call nearest airport for emergency landing
case .EngineFailure(let reason):
print(reason) // let the mechanic know the reason
case .DamagedWing:
// Assess the damage and determine if the president can make it
}
}
Disabilitare la propagazione degli errori
I creatori di Swift hanno prestato molta attenzione a rendere il linguaggio espressivo e la gestione degli errori è esattamente questo, espressivo. Se si tenta di richiamare una funzione che può generare un errore, la chiamata alla funzione deve essere preceduta dalla parola chiave try. La parola chiave try non è magica. Tutto ciò che fa è rendere lo sviluppatore consapevole della capacità di lancio della funzione.
Ad esempio, il codice seguente utilizza una funzione loadImage (atPath :), che carica la risorsa immagine in un determinato percorso o genera un errore se l'immagine non può essere caricata. In questo caso, poiché l'immagine viene fornita con l'applicazione, non verrà generato alcun errore in fase di runtime, quindi è opportuno disabilitare la propagazione dell'errore.
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
Crea un errore personalizzato con descrizione localizzata
Crea enum
di errori personalizzati
enum RegistrationError: Error {
case invalidEmail
case invalidPassword
case invalidPhoneNumber
}
Crea extension
di RegistrationError
per gestire la descrizione localizzata.
extension RegistrationError: LocalizedError {
public var errorDescription: String? {
switch self {
case .invalidEmail:
return NSLocalizedString("Description of invalid email address", comment: "Invalid Email")
case .invalidPassword:
return NSLocalizedString("Description of invalid password", comment: "Invalid Password")
case .invalidPhoneNumber:
return NSLocalizedString("Description of invalid phoneNumber", comment: "Invalid Phone Number")
}
}
}
Errore di gestione:
let error: Error = RegistrationError.invalidEmail
print(error.localizedDescription)