Ziel-C: Behauptung vs. Ausnahme vs. Fehler

79

Wann sollte ich in Cocoa NSAssert, NSException, NSError verwenden?

Folgendes habe ich mir gedacht:

NSAssert - Wenn Sie ein Client-Programm erstellen, das zum eigenen Vorteil des Programmierers verwendet wird, um Regeln, Konventionen, Annahmen oder Vor- und Nachbedingungen zu überprüfen?

NSException - Wenn Sie eine Bibliothek eines Drittanbieters für andere Programmierer erstellen, die die Bibliothek verwenden, damit diese sofort wissen, wenn eine Eingabe ungültig ist?

NSError - Wenn Sie eine Schnittstelle zu einem externen System herstellen, um Daten wie eine Datei, eine Datenbank oder einen Webdienst abzurufen , von denen nicht garantiert wird, dass sie mir ein Ergebnis liefern?

Tobias
quelle

Antworten:

103

Ein NSAssert löst eine Ausnahme aus, wenn dies fehlschlägt. NSAssert bietet also eine kurze und einfache Möglichkeit zum Schreiben und Überprüfen aller Annahmen, die Sie in Ihrem Code getroffen haben. Es ist (meiner Meinung nach) keine Alternative zu Ausnahmen, sondern nur eine Abkürzung. Wenn eine Behauptung fehlschlägt, ist in Ihrem Code ein furchtbarer Fehler aufgetreten, und das Programm sollte nicht fortgesetzt werden.

Zu beachten ist, dass NSAssert in einem Release-Build nicht in Ihren Code kompiliert wird. Daher wird dies normalerweise zur Überprüfung der Integrität während der Entwicklung verwendet. Ich neige dazu, ein benutzerdefiniertes Assert-Makro zu verwenden, das immer aktiv ist.

Die Zeiten, in denen Sie @throwIhre eigene NSException verwenden würden, sind, wenn Sie sie definitiv in einem Release-Build möchten, und in Dingen wie öffentlichen Bibliotheken / Schnittstellen, wenn einige Argumente ungültig sind oder Sie falsch aufgerufen wurden. Beachten Sie, dass @catcheine Ausnahme nicht unbedingt üblich ist, und führen Sie Ihre Anwendung weiter aus. Wenn Sie dies mit einigen Standardbibliotheken von Apple (z. B. Core Data) versuchen, können schlimme Dinge passieren. Ähnlich wie bei einer Behauptung sollte die App im Allgemeinen ziemlich schnell beendet werden, wenn eine Ausnahme ausgelöst wird, da dies bedeutet, dass irgendwo ein Programmierfehler vorliegt.

NSErrors sollten in Ihren Bibliotheken / Schnittstellen für Fehler verwendet werden, bei denen es sich nicht um Programmierfehler handelt und die behoben werden können. Sie können dem Anrufer Informationen / Fehlercodes bereitstellen, die den Fehler sauber behandeln, den Benutzer gegebenenfalls benachrichtigen und die Ausführung fortsetzen können. Dies gilt normalerweise für Dinge wie einen Fehler, bei dem die Datei nicht gefunden wurde, oder einen anderen nicht schwerwiegenden Fehler.

Mike Weller
quelle
15
Um es stärker auszudrücken, sollte eine NSException nicht verwendet werden, um einen behebbaren Fehler anzuzeigen.
bbum
28
Mit anderen Worten: Obj-Cs NSException == Java's Error-Klasse und Obj-Cs NSError == Java's Exception-Klasse. Ein Hoch auf die Beständigkeit!
Tustin2121
2
Tatsächlich wird NSAssert in Ihren Code kompiliert, wenn Sie NS_BLOCK_ASSERTIONS nicht zu Ihren vorkompilierten Präfixdateien hinzufügen. Lesen Sie die Antwort unten (nur 50, um jetzt zu empfehlen :)
likid1412
3

Die Konvention in Cocoa ist, dass eine Ausnahme einen Programmiererfehler anzeigt. Viele Codes, einschließlich Framework-Code, funktionieren nach dem Auslösen einer Ausnahme nicht ordnungsgemäß.

Jede Art von Fehler, der behoben werden kann, wird durch eine dargestellt NSError. Es gibt auch ein System, NSErrorum dem Benutzer s zu präsentieren . Wie Sie sagen, ist dies hauptsächlich für fehlbare externe Ressourcen nützlich.

Konzeptionell ist eine Behauptung eine Aussage, dass ein gegebenes Prädikat immer als wahr bewertet wird; Ist dies nicht der Fall, ist das Programm fehlerhaft. Während das Verhalten geändert werden kann, ist die NSAssertFamilie standardmäßig eine bequeme Möglichkeit, NSInternalInconsistencyExceptions zu werfen (mit der Option, sie in Release-Builds zu deaktivieren).

Jens Ayton
quelle
2

Bearbeiten: In Xcode 4.2 sind Zusicherungen für Release-Builds standardmäßig deaktiviert.

Jetzt wird NSAssert in einem Release-Build nicht in Ihren Code kompiliert , Sie können ihn jedoch in den Build-Einstellungen ändern


@ Mike Weller, Ihre Antwort ist falsch.

Zu beachten ist, dass NSAssert in einem Release-Build nicht in Ihren Code kompiliert wird. Daher wird dies normalerweise zur Überprüfung der Integrität während der Entwicklung verwendet.

Tatsächlich wird NSAssert in Ihren Code kompiliert, wenn Sie NS_BLOCK_ASSERTIONSIhre vorkompilierten Präfixdateien nicht hinzufügen .

Im Technical Note TN2190 finden wir:

Makros wie NDEBUG zum Deaktivieren von C assert oder NS_BLOCK_ASSERTIONS zum Deaktivieren von Foundation's NSAssert sind wichtig, um sie für Ihre vorkompilierten Präfixdateien anzugeben

Oder lesen Sie Folgendes : Woher wissen Sie, ob NSAssert in Release-Builds deaktiviert ist?

likid1412
quelle
1

Im Allgemeinen werden Ausnahmen verwendet, um Programmiererfehler zu signalisieren - dies sind Dinge, die nicht passieren sollten. Fehler werden verwendet, um Fehlerbedingungen zu signalisieren, die im normalen Betrieb des Programms auftreten können - Benutzerfehler im Grunde oder externe Bedingungen, die wahr sein müssen, aber möglicherweise nicht. Der Versuch, ein gesperrtes Element in einem Dokument zu löschen, könnte ein Fehler sein, und der Versuch, eine Datei ohne Internetverbindung herunterzuladen, wäre ein Fehler, aber der Versuch, auf ein ungültiges Element in einer Sammlung zuzugreifen, wäre eine Ausnahme.

Behauptungen werden normalerweise beim Testen verwendet, und AFAIK wird nicht wie die anderen als allgemeiner Fehlerbehandlungsmechanismus verwendet.

Futter
quelle
Assertions können verwendet werden, um Invarianten zu erzwingen. Erzwingt beispielsweise NSParameterAssert(someParam != nil);die Invariante, dass der angegebene Parameter nicht Null sein darf.
Lily Ballard
@ Kevin Ballard: Behauptungen werden normalerweise aus Release-Builds definiert, oder zumindest wurden sie zuletzt von mir überprüft. Wie ich bereits sagte, handelt es sich also nicht um einen allgemeinen Fehlerbehandlungsmechanismus.
Chuck
1
Sie können sein, werden aber standardmäßig nicht weggelassen. Sie müssen eine Build-Einstellung ändern, um dieses Verhalten zu erhalten.
Lily Ballard