Ich versuche es in Swift 2 mit neuen Fehlern zu verstehen. Folgendes habe ich getan: Ich habe zuerst eine Fehleraufzählung deklariert:
enum SandwichError: ErrorType {
case NotMe
case DoItYourself
}
Und dann habe ich eine Methode deklariert, die einen Fehler auslöst (keine Ausnahme, Leute. Es ist ein Fehler.). Hier ist diese Methode:
func makeMeSandwich(names: [String: String]) throws -> String {
guard let sandwich = names["sandwich"] else {
throw SandwichError.NotMe
}
return sandwich
}
Das Problem ist von der anrufenden Seite. Hier ist der Code, der diese Methode aufruft:
let kitchen = ["sandwich": "ready", "breakfeast": "not ready"]
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
print("Not me error")
} catch SandwichError.DoItYourself {
print("do it error")
}
Nachdem der do
Zeilencompiler sagt Errors thrown from here are not handled because the enclosing catch is not exhaustive
. Aber meiner Meinung nach ist es erschöpfend, weil es nur zwei Fälle in der SandwichError
Aufzählung gibt.
Für reguläre switch-Anweisungen kann swift verstehen, dass es erschöpfend ist, wenn jeder Fall behandelt wird.
do
Blöcke auf der obersten Ebene zuzulassen , die nicht erschöpfend sind. Wenn Sie das Do in eine nicht werfende Funktion einwickeln, wird der Fehler generiert.Antworten:
Das Swift 2-Fehlerbehandlungsmodell weist zwei wichtige Punkte auf: Vollständigkeit und Ausfallsicherheit. Zusammen laufen sie auf Ihre
do
/catch
-Anweisung hinaus und müssen jeden möglichen Fehler abfangen, nicht nur die, von denen Sie wissen, dass Sie sie werfen können.Beachten Sie, dass Sie nicht deklarieren, welche Arten von Fehlern eine Funktion auslösen kann, sondern nur, ob sie überhaupt auslöst. Es ist ein Null-Eins-Unendlich-Problem: Als jemand, der eine Funktion definiert, die von anderen (einschließlich Ihres zukünftigen Selbst) verwendet werden soll, möchten Sie nicht jeden Client Ihrer Funktion dazu bringen müssen, sich an jede Änderung in der Implementierung Ihrer Funktion anzupassen Funktion, einschließlich der Fehler, die es auslösen kann. Sie möchten, dass Code, der Ihre Funktion aufruft, solchen Änderungen standhält.
Da Ihre Funktion nicht sagen kann, welche Art von Fehlern sie auslöst (oder in Zukunft auslösen könnte),
catch
wissen die Blöcke, die sie abfangen, nicht, welche Arten von Fehlern sie auslösen könnte. Zusätzlich zu den Fehlertypen, die Sie kennen, müssen Sie diejenigen, die Sie nicht kennen, mit einer universellencatch
Anweisung behandeln. Wenn Ihre Funktion also die Menge der Fehler ändert, die sie in Zukunft auslöst, werden die Anrufer diese weiterhin abfangen Fehler.Aber lasst uns hier nicht aufhören. Denken Sie noch etwas über diese Resilienzidee nach. So wie Sie Ihr Sandwich entworfen haben, müssen Sie Fehler an jedem Ort beschreiben, an dem Sie sie verwenden. Das bedeutet, dass Sie jedes Mal, wenn Sie die Fehlerfälle ändern, jeden Ort ändern müssen, an dem sie verwendet werden ... nicht sehr lustig.
Die Idee hinter der Definition Ihrer eigenen Fehlertypen besteht darin, dass Sie solche Dinge zentralisieren können. Sie können eine
description
Methode für Ihre Fehler definieren:Und dann kann Ihr Fehlerbehandlungscode Ihren Fehlertyp auffordern, sich selbst zu beschreiben - jetzt kann jeder Ort, an dem Sie Fehler behandeln, denselben Code verwenden und auch mögliche zukünftige Fehlerfälle behandeln.
Dies ebnet auch den Weg für Fehlertypen (oder Erweiterungen auf ihnen), um andere Arten der Fehlermeldung zu unterstützen. Sie könnten beispielsweise eine Erweiterung für Ihren Fehlertyp haben, die weiß, wie eine
UIAlertController
Fehlermeldung für einen iOS-Benutzer angezeigt wird.quelle
error caught in main()
alles, was Sie gesagt haben, vernünftig klingt, kann ich dieses Verhalten nicht reproduzieren.try
Ausdrucks im Produktionscode zu vermeiden, da dies einen Laufzeitfehler verursachen und zum Absturz Ihrer Anwendung führen kanntry!
. Es gibt wohl auch gültige, "sichere" Anwendungsfälle für die verschiedenen "Force" -Operationen in Swift (Auspacken, Ausprobieren usw.), selbst für Produktionscode - wenn Sie durch Vorbedingungen oder Konfiguration die Möglichkeit eines Fehlers zuverlässig ausgeschlossen haben, könnte dies der Fall sein Es ist sinnvoller, einen Kurzschluss auf einen sofortigen Fehler kurzzuschließen, als einen nicht testbaren Fehlerbehandlungscode zu schreiben.SandwichError
sinnvoll , diese Logik in die Klasse einzufügen. Ich vermute jedoch, dass für die meisten Fehler die Fehlerbehandlungslogik nicht so gekapselt werden kann. Dies liegt daran, dass normalerweise die Kenntnis des Kontextes des Anrufers erforderlich ist (ob ein Fehler wiederhergestellt oder erneut versucht oder ein Fehler im Upstream gemeldet werden soll usw.). Mit anderen Worten, ich vermute, dass das häufigste Muster ohnehin darin bestehen müsste, mit bestimmten Fehlertypen übereinzustimmen.Ich vermute, dass dies noch nicht richtig implementiert wurde. Das Swift Programming Guide scheint definitiv zu implizieren, dass der Compiler erschöpfende Übereinstimmungen "wie eine switch-Anweisung" ableiten kann. Es wird nicht erwähnt, dass ein General benötigt
catch
wird, um erschöpfend zu sein.Sie werden auch feststellen, dass sich der Fehler in der
try
Zeile befindet und nicht am Ende des Blocks. Das heißt, der Compiler kann irgendwann feststellen, welchetry
Anweisung im Block nicht behandelte Ausnahmetypen hat.Die Dokumentation ist allerdings etwas mehrdeutig. Ich habe das Video "Was ist neu in Swift?" Durchgesehen und konnte keine Hinweise finden. Ich werde es weiter versuchen.
Aktualisieren:
Wir sind jetzt bis zur Beta 3 ohne Hinweis auf eine ErrorType-Inferenz. Ich glaube jetzt, wenn dies jemals geplant war (und ich denke immer noch, dass es irgendwann war), hat der dynamische Versand von Protokollerweiterungen es wahrscheinlich beendet.
Beta 4 Update:
Xcode 7b4 hat die Unterstützung für Dokumentkommentare hinzugefügt
Throws:
, mit denen "dokumentiert werden soll, welche Fehler ausgelöst werden können und warum". Ich denke , das zumindest bietet einigen Mechanismus Fehler API Verbraucher zu kommunizieren. Wer braucht ein Typensystem, wenn Sie Dokumentation haben!Ein weiteres Update:
Nachdem er für die automatische einige Zeit der Hoffnung ,
ErrorType
Inferenz und arbeiten heraus , was die Grenzen dieses Modells wäre, habe ich meine Meinung geändert - das ist es, was ich hoffe , Apple - Geräte statt. Im Wesentlichen:Noch ein Update
Die Gründe für die Fehlerbehandlung von Apple finden Sie jetzt hier . Es gab auch einige interessante Diskussionen auf der Mailingliste von Swift-Evolution . Im Wesentlichen ist John McCall gegen typisierte Fehler, da er glaubt, dass die meisten Bibliotheken ohnehin einen generischen Fehlerfall enthalten werden und dass typisierte Fehler, abgesehen von Boilerplate, wahrscheinlich nicht viel zum Code beitragen (er verwendete den Begriff "aspirational bluff"). Chris Lattner sagte, er sei offen für Tippfehler in Swift 3, wenn dies mit dem Resilienzmodell funktioniert.
quelle
Swift befürchtet, dass Ihre case-Anweisung nicht alle Fälle abdeckt. Um dies zu beheben, müssen Sie einen Standardfall erstellen:
quelle
catch
Aussagen aufgeführt.func method() throws(YourErrorEnum)
, oderthrows(YourEnum.Error1, .Error2, .Error3)
trotzdem wissen Sie, was geworfen werden kannIch war auch enttäuscht über den Mangel an Typ, den eine Funktion auslösen kann, aber ich bekomme ihn jetzt dank @rickster und fasse ihn folgendermaßen zusammen: Nehmen wir an, wir könnten den Typ angeben, den eine Funktion auslöst, wir hätten so etwas:
Das Problem ist, dass selbst wenn wir in myFunctionThatThrows nichts ändern, wenn wir MyError nur einen Fehlerfall hinzufügen:
Wir sind geschraubt, weil unser Do / Try / Catch nicht mehr vollständig ist, ebenso wie jeder andere Ort, an dem wir Funktionen aufgerufen haben, die MyError auslösen
quelle
catch {}
am Ende jedes Blocks ist jedoch wohl schlechter. Ich hoffe, dass der Compiler irgendwann automatisch auf Fehlertypen schließen wird, wo dies möglich ist, aber ich konnte dies nicht bestätigen.Jetzt Nummer validieren:
quelle
Erstellen Sie eine Aufzählung wie folgt:
Erstellen Sie eine Methode wie:
Überprüfen Sie nun, ob ein Fehler vorliegt oder nicht, und behandeln Sie ihn:
quelle