Quando si chiama una funzione dichiarata con throws
in Swift, è necessario annotare il sito di chiamata della funzione con try
o try!
. Ad esempio, data una funzione di lancio:
func willOnlyThrowIfTrue(value: Bool) throws {
if value { throw someError }
}
questa funzione può essere chiamata come:
func foo(value: Bool) throws {
try willOnlyThrowIfTrue(value)
}
Qui annotiamo la chiamata con try
, che chiama al lettore che questa funzione può generare un'eccezione e che eventuali righe di codice seguenti potrebbero non essere eseguite. Dobbiamo anche annotare questa funzione con throws
, perché questa funzione potrebbe generare un'eccezione (ad esempio, quando viene willOnlyThrowIfTrue()
generata, quindifoo
viene generata ridiscuterà automaticamente l'eccezione verso l'alto.
Se vuoi chiamare una funzione che è dichiarata come possibilmente lanciata, ma che sai che non verrà lanciata nel tuo caso perché le stai dando l'input corretto, puoi usare try!
.
func bar() {
try! willOnlyThrowIfTrue(false)
}
In questo modo, quando si garantisce che il codice non verrà emesso, non è necessario inserire un codice extra sulla piastra di cottura per disabilitare la propagazione delle eccezioni.
try!
viene applicato in fase di esecuzione: se si utilizza try!
e la funzione termina il lancio, l'esecuzione del programma verrà chiusa con un errore di runtime.
La maggior parte del codice di gestione delle eccezioni dovrebbe apparire come sopra: o semplicemente si propagano le eccezioni verso l'alto quando si verificano o si impostano condizioni tali da escludere eventuali eccezioni. Qualsiasi ripulitura di altre risorse nel codice dovrebbe avvenire tramite la distruzione di oggetti (ad esempio deinit()
) o talvolta tramite defer
codice ed.
func baz(value: Bool) throws {
var filePath = NSBundle.mainBundle().pathForResource("theFile", ofType:"txt")
var data = NSData(contentsOfFile:filePath)
try willOnlyThrowIfTrue(value)
// data and filePath automatically cleaned up, even when an exception occurs.
}
Se per qualsiasi motivo hai il codice di pulizia che deve essere eseguito ma non è in una deinit()
funzione, puoi usare defer
.
func qux(value: Bool) throws {
defer {
print("this code runs when the function exits, even when it exits by an exception")
}
try willOnlyThrowIfTrue(value)
}
La maggior parte del codice che si occupa delle eccezioni li ha semplicemente propagati verso l'alto ai chiamanti, facendo pulizia sulla strada tramite deinit()
odefer
. Questo perché la maggior parte del codice non sa cosa fare degli errori; sa cosa è andato storto, ma non ha abbastanza informazioni su ciò che un codice di livello superiore sta cercando di fare per sapere cosa fare dell'errore. Non sa se presentare una finestra di dialogo all'utente è appropriato, se deve riprovare o se qualcos'altro è appropriato.
Il codice di livello superiore, tuttavia, dovrebbe sapere esattamente cosa fare in caso di errore. Pertanto, le eccezioni consentono a errori specifici di risalire da dove si verificano inizialmente a dove possono essere gestiti.
La gestione delle eccezioni viene effettuata tramite catch
istruzioni.
func quux(value: Bool) {
do {
try willOnlyThrowIfTrue(value)
} catch {
// handle error
}
}
Puoi avere più dichiarazioni catch, ognuna con un diverso tipo di eccezione.
do {
try someFunctionThatThowsDifferentExceptions()
} catch MyErrorType.errorA {
// handle errorA
} catch MyErrorType.errorB {
// handle errorB
} catch {
// handle other errors
}
Per maggiori dettagli sulle migliori pratiche con eccezioni, consultare http://exceptionsafecode.com/ . Si rivolge specificamente al C ++, ma dopo aver esaminato il modello di eccezione Swift, credo che le basi si applichino anche a Swift.
Per dettagli sulla sintassi di Swift e sul modello di gestione degli errori, consultare il libro The Swift Programming Language (Swift 2 Prerelease) .