it-swarm.com.de

eine Ausnahme in Objective-C / Kakao zu werfen

Was ist der beste Weg, um eine Ausnahme in Objective-C/Cocoa zu werfen?

409
Steph Thirion

Ich benutze [NSException raise:format:] wie folgt:

[NSException raise:@"Invalid foo value" format:@"foo of %d is invalid", foo];
523
e.James

Ein Wort der Vorsicht hier. Im Gegensatz zu vielen ähnlichen Sprachen sollten Sie in Objective-C generell versuchen, Ausnahmen für häufige Fehlersituationen zu vermeiden, die im normalen Betrieb auftreten können.

Apples Dokumentation für Obj-C 2. gibt Folgendes an: "Wichtig: Ausnahmen sind in Objective-C ressourcenintensiv. Sie sollten keine Ausnahmen für die allgemeine Ablaufsteuerung oder einfach zum Anzeigen von Fehlern verwenden (z. B. eine Datei, auf die nicht zugegriffen werden kann) "

Apples konzeptionelle Dokumentation zur Ausnahmebehandlung erklärt das Gleiche, aber mit mehr Worten: "Wichtig: Sie sollten die Verwendung von Ausnahmen für Programmier- oder unerwartete Laufzeitfehler wie Zugriff auf außerhalb der Grenzen liegende Auflistungen und Mutationsversuche vorbehalten Unveränderliche Objekte, Senden einer ungültigen Nachricht und Unterbrechen der Verbindung zum Windows-Server. Diese Art von Fehlern werden normalerweise mit Ausnahmen behoben, wenn eine Anwendung erstellt wird, und nicht zur Laufzeit. [.....] Anstelle von Ausnahmen, Fehlerobjekte (NSError) und der Cocoa-Fehlerübermittlungsmechanismus sind die empfohlene Methode, um erwartete Fehler in Cocoa-Anwendungen zu kommunizieren. "

Der Grund dafür ist zum einen, dass Programmiersprachen in Objective-C eingehalten werden (Rückgabewerte in einfachen Fällen und By-Reference-Parameter (häufig die NSError-Klasse) in komplexeren Fällen), zum anderen, dass das Auslösen und Abfangen von Ausnahmen viel teurer ist und zum anderen Schließlich (und das Wichtigste) ist, dass Objective-C-Ausnahmen ein dünner Wrapper um die Funktionen setjmp () und longjmp () von C sind, der Ihre vorsichtige Speicherbehandlung im Wesentlichen durcheinanderbringt, siehe diese Erklärung .

256
harms
@throw([NSException exceptionWith…])
60
Peter Hosey

Ich habe nicht den Repräsentanten, der die Antwort von eJames kommentiert, also muss ich meine wohl hier einfügen. Für diejenigen, die aus einem Java Hintergrund stammen, werden Sie sich daran erinnern, dass Java zwischen Ausnahme und RuntimeException unterscheidet. Ausnahme ist eine aktivierte Ausnahme, und RuntimeException ist deaktiviert. Insbesondere , Java schlägt vor, geprüfte Ausnahmen für "normale Fehlerbedingungen" und ungeprüfte Ausnahmen für "Laufzeitfehler, die durch einen Programmiererfehler verursacht werden" zu verwenden. Es scheint, dass Objective-C-Ausnahmen an den gleichen Stellen verwendet werden sollten, an denen Sie würde eine ungeprüfte Ausnahme verwenden, und Fehlercode-Rückgabewerte oder NSError-Werte werden an Stellen bevorzugt, an denen Sie eine geprüfte Ausnahme verwenden würden.

33

Ich denke, um konsistent zu sein, ist es besser, @throw mit Ihrer eigenen Klasse zu verwenden, die die NSException erweitert. Dann verwenden Sie die gleichen Notationen für try catch finally:

@try {
.....
}
@catch{
...
}
@finally{
...
}

Apple erklärt hier, wie man Ausnahmen auslöst und behandelt: Ausnahmen abfängtAusnahmen auslöst

15
rustyshelf

Seit ObjC 2.0 sind Objective-C-Ausnahmen kein Wrapper mehr für Cs setjmp () longjmp () und kompatibel mit C++ - Ausnahmen. @Try ist "kostenlos", aber das Auslösen und Abfangen von Ausnahmen ist weitaus teurer.

Assertions (die NSAssert- und NSCAssert-Makrofamilie verwenden) werfen jedenfalls NSException, und das ist vernünftig, um sie als Ries-Zustände zu verwenden.

14
Psycho

Verwenden Sie NSError, um Fehler und keine Ausnahmen zu kommunizieren.

Wichtige Punkte zu NSError:

  • Mit NSError können C-Fehlercodes (Ganzzahlen) die Grundursache eindeutig identifizieren und dem Fehlerbehandler hoffentlich die Überwindung des Fehlers ermöglichen. Sie können Fehlercodes aus C-Bibliotheken wie SQLite sehr einfach in NSError-Instanzen einbinden.

  • NSError hat auch den Vorteil, ein Objekt zu sein, und bietet eine Möglichkeit, den Fehler mit seinem UserInfo-Dictionary-Member genauer zu beschreiben.

  • Das Beste ist jedoch, dass NSError NICHT ausgelöst werden KANN, um eine proaktivere Fehlerbehandlung zu fördern, im Gegensatz zu anderen Sprachen, bei denen die heiße Kartoffel immer weiter nach oben geworfen wird und erst dann an den Benutzer und gemeldet werden kann nicht in irgendeiner sinnvollen Weise gehandhabt (nicht, wenn Sie daran glauben, OOPs größtem Grundsatz des Versteckens von Informationen zu folgen).

Referenzlink: Referenz

8

So habe ich es aus "The Big Nerd Ranch Guide (4. Auflage)" gelernt:

@throw [NSException exceptionWithName:@"Something is not right exception"
                               reason:@"Can't perform this operation because of this or that"
                             userInfo:nil];
7
Johannes

Sie können zwei Methoden zum Auslösen von Ausnahmen im try catch-Block verwenden

@throw[NSException exceptionWithName];

oder die zweite Methode

NSException e;
[e raise];
6
Subbu

Ich glaube, Sie sollten niemals Ausnahmen verwenden, um den normalen Programmfluss zu steuern. Es sollten jedoch Ausnahmen ausgelöst werden, wenn ein Wert nicht mit einem gewünschten Wert übereinstimmt.

Wenn zum Beispiel eine Funktion einen Wert akzeptiert und dieser Wert niemals Null sein darf, ist es in Ordnung, eine Ausnahme auszulösen, anstatt zu versuchen, etwas 'Kluges' zu tun ...

Ries

3
R. van Twisk

Beispielcode für case: @throw ([NSException exceptionWithName: ...

- (void)parseError:(NSError *)error
       completionBlock:(void (^)(NSString *error))completionBlock {


    NSString *resultString = [NSString new];

    @try {

    NSData *errorData = [NSData dataWithData:error.userInfo[@"SomeKeyForData"]];

    if(!errorData.bytes) {

        @throw([NSException exceptionWithName:@"<Set Yours exc. name: > Test Exc" reason:@"<Describe reason: > Doesn't contain data" userInfo:nil]);
    }


    NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorData
                                                                 options:NSJSONReadingAllowFragments
                                                                   error:&error];

    resultString = dictFromData[@"someKey"];
    ...


} @catch (NSException *exception) {

      NSLog( @"Caught Exception Name: %@", exception.name);
      NSLog( @"Caught Exception Reason: %@", exception.reason );

    resultString = exception.reason;

} @finally {

    completionBlock(resultString);
}

}

Verwenden von:

[self parseError:error completionBlock:^(NSString *error) {
            NSLog(@"%@", error);
        }];

Ein weiterer fortgeschrittener Anwendungsfall:

- (void)parseError:(NSError *)error completionBlock:(void (^)(NSString *error))completionBlock {

NSString *resultString = [NSString new];

NSException* customNilException = [NSException exceptionWithName:@"NilException"
                                                          reason:@"object is nil"
                                                        userInfo:nil];

NSException* customNotNumberException = [NSException exceptionWithName:@"NotNumberException"
                                                                reason:@"object is not a NSNumber"
                                                              userInfo:nil];

@try {

    NSData *errorData = [NSData dataWithData:error.userInfo[@"SomeKeyForData"]];

    if(!errorData.bytes) {

        @throw([NSException exceptionWithName:@"<Set Yours exc. name: > Test Exc" reason:@"<Describe reason: > Doesn't contain data" userInfo:nil]);
    }


    NSDictionary *dictFromData = [NSJSONSerialization JSONObjectWithData:errorData
                                                                 options:NSJSONReadingAllowFragments
                                                                   error:&error];

    NSArray * array = dictFromData[@"someArrayKey"];

    for (NSInteger i=0; i < array.count; i++) {

        id resultString = array[i];

        if (![resultString isKindOfClass:NSNumber.class]) {

            [customNotNumberException raise]; // <====== HERE is just the same as: @throw customNotNumberException;

            break;

        } else if (!resultString){

            @throw customNilException;        // <======

            break;
        }

    }

} @catch (SomeCustomException * sce) {
    // most specific type
    // handle exception ce
    //...
} @catch (CustomException * ce) {
    // most specific type
    // handle exception ce
    //...
} @catch (NSException *exception) {
    // less specific type

    // do whatever recovery is necessary at his level
    //...
    // rethrow the exception so it's handled at a higher level

    @throw (SomeCustomException * customException);

} @finally {
    // perform tasks necessary whether exception occurred or not

}

}

0
Aleksandr B.

Sie sollten Ausnahmen nur dann auslösen, wenn Sie sich in einer Situation befinden, die auf einen Programmierfehler hinweist, und die Ausführung der Anwendung stoppen möchten. Aus diesem Grund empfiehlt es sich, Ausnahmen mit den Makros NSAssert und NSParameterAssert auszulösen und sicherzustellen, dass NS_BLOCK_ASSERTIONS nicht definiert ist.

0
gnasher729