Wenn Sie eine Funktion aufrufen, mit der throws
in Swift deklariert wurde, müssen Sie die Funktionsaufrufsite mit try
oder mit Anmerkungen versehen try!
. Zum Beispiel mit einer Wurffunktion:
func willOnlyThrowIfTrue(value: Bool) throws {
if value { throw someError }
}
Diese Funktion kann wie folgt aufgerufen werden:
func foo(value: Bool) throws {
try willOnlyThrowIfTrue(value)
}
Hier kommentieren wir den Aufruf mit try
, wodurch der Leser darauf hingewiesen wird, dass diese Funktion möglicherweise eine Ausnahme auslöst und die folgenden Codezeilen möglicherweise nicht ausgeführt werden. Wir haben diese Funktion auch mit zu annotieren throws
, da diese Funktion eine Ausnahme auslösen könnte (dh, wenn willOnlyThrowIfTrue()
wirft, dann foo
wird die Ausnahme nach oben automatisch erneut auslösen.
Wenn Sie eine Funktion aufrufen möchten, die als möglicherweise auslösend deklariert ist, von der Sie jedoch wissen, dass sie in Ihrem Fall nicht ausgelöst wird, weil Sie sie korrekt eingeben, können Sie sie verwenden try!
.
func bar() {
try! willOnlyThrowIfTrue(false)
}
Auf diese Weise müssen Sie, wenn Sie sicherstellen, dass der Code nicht ausgelöst wird, keinen zusätzlichen Code für das Boilerplate eingeben, um die Weitergabe von Ausnahmen zu deaktivieren.
try!
wird zur Laufzeit erzwungen: Wenn Sie verwenden try!
und die Funktion am Ende ausgelöst wird, wird die Ausführung Ihres Programms mit einem Laufzeitfehler beendet.
Der meiste Code für die Ausnahmebehandlung sollte wie folgt aussehen: Entweder Sie verbreiten Ausnahmen einfach nach oben, wenn sie auftreten, oder Sie richten Bedingungen so ein, dass ansonsten mögliche Ausnahmen ausgeschlossen sind. Jede Bereinigung anderer Ressourcen in Ihrem Code sollte durch Objektzerstörung (dh deinit()
) oder manchmal durch defer
ed-Code erfolgen.
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.
}
Wenn Sie aus irgendeinem Grund Bereinigungscode haben, der ausgeführt werden muss, aber nicht in einer deinit()
Funktion enthalten ist, können Sie ihn verwenden 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)
}
Der meiste Code, der sich mit Ausnahmen befasst, lässt sie einfach nach oben an Anrufer weitergeben und bereinigt auf dem Weg über deinit()
oder defer
. Dies liegt daran, dass die meisten Codes nicht wissen, wie sie mit Fehlern umgehen sollen. Es weiß, was schief gelaufen ist, aber es gibt nicht genügend Informationen darüber, was ein Code höherer Ebene versucht, um zu wissen, was gegen den Fehler zu tun ist. Es weiß nicht, ob es angemessen ist, dem Benutzer einen Dialog zu präsentieren, oder ob es erneut versucht werden sollte oder ob etwas anderes angemessen ist.
Code auf höherer Ebene sollte jedoch genau wissen, was im Fehlerfall zu tun ist. Ausnahmen ermöglichen es also, dass bestimmte Fehler von dem Ort, an dem sie anfänglich auftreten, zu dem Ort aufsteigen, an dem sie behandelt werden können.
Die Behandlung von Ausnahmen erfolgt über catch
Anweisungen.
func quux(value: Bool) {
do {
try willOnlyThrowIfTrue(value)
} catch {
// handle error
}
}
Sie können mehrere catch-Anweisungen haben, von denen jede eine andere Art von Ausnahme abfängt.
do {
try someFunctionThatThowsDifferentExceptions()
} catch MyErrorType.errorA {
// handle errorA
} catch MyErrorType.errorB {
// handle errorB
} catch {
// handle other errors
}
Weitere Informationen zu Best Practices mit Ausnahmen finden Sie unter http://exceptionsafecode.com/ . Es richtet sich speziell an C ++, aber nach Prüfung des Swift-Ausnahmemodells gelten die Grundlagen meines Erachtens auch für Swift.
Einzelheiten zur Swift-Syntax und zum Fehlerbehandlungsmodell finden Sie im Buch The Swift Programming Language (Swift 2 Prerelease) .