Was ist der beste Weg, um eine Ausnahme in objective-c/cocoa zu werfen?
Antworten
Zu viele Anzeigen?Sie sollten Ausnahmen nur dann auslösen, wenn Sie sich in einer Situation befinden, die auf einen Programmierfehler hindeutet, und die Ausführung der Anwendung stoppen wollen. Daher ist es am besten, Ausnahmen mit den Makros NSAssert und NSParameterAssert zu erzeugen und sicherzustellen, dass NS_BLOCK_ASSERTIONS nicht definiert ist.
Beispielcode für den Fall: @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:
[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
}
}
Es gibt keinen Grund, Ausnahmen nicht auch in Objective C zu verwenden, um Ausnahmen von Geschäftsregeln zu kennzeichnen. Apple kann sagen, benutze NSError, wen interessiert das. Objective C gibt es schon lange, und früher sagte die gesamte C++-Dokumentation dasselbe. Der Grund, warum es keine Rolle spielt, wie teuer das Werfen und Abfangen einer Ausnahme ist, ist, dass die Lebensdauer einer Ausnahme äußerst kurz ist und... es ist eine AUSNAHME zum normalen Ablauf. Ich habe noch nie in meinem Leben jemanden sagen hören: "Mann, diese Ausnahme hat aber lange gebraucht, um ausgelöst und abgefangen zu werden.
Es gibt auch Leute, die Objective C selbst für zu teuer halten und stattdessen in C oder C++ programmieren. Daher ist die Aussage, immer NSError zu verwenden, schlecht informiert und paranoid.
Aber die Frage dieses Threads wurde noch nicht beantwortet, was der beste Weg, um eine Ausnahme zu werfen. Die Möglichkeiten, NSError zurückzugeben, sind offensichtlich.
So ist es: [NSException raise:... @throw [[NSException alloc] initWithName.... oder @throw [[MyCustomException... ?
Ich verwende die Regel "angekreuzt/unangekreuzt" hier etwas anders als oben.
Der wirkliche Unterschied zwischen (hier wird die Java-Metapher verwendet) geprüft/ungeprüft ist wichtig --> ob Sie die Ausnahme beheben können. Und mit wiederherstellen meine ich nicht nur NICHT abstürzen.
Ich verwende also benutzerdefinierte Ausnahmeklassen mit @throw für wiederherstellbare Ausnahmen, weil es wahrscheinlich ist, dass ich eine App-Methode habe, die nach bestimmten Arten von Fehlern in mehreren @catch-Blöcke. Wenn meine Anwendung zum Beispiel ein Geldautomat ist, würde ich einen @catch-Block für die "WithdrawalRequestExceedsBalanceException".
Ich verwende NSException:raise für Laufzeitausnahmen, da ich keine Möglichkeit habe, die Ausnahme zu beheben, außer sie auf einer höheren Ebene abzufangen und zu protokollieren. Und theres keinen Sinn bei der Erstellung einer benutzerdefinierten Klasse für das.
Jedenfalls mache ich das so, aber wenn es eine bessere, ähnlich ausdrucksstarke Methode gibt, würde ich das auch gerne wissen. In meinem eigenen Code, seit ich aufgehört habe, C vor einer verdammt langen Zeit zu programmieren, gebe ich nie einen NSError zurück, selbst wenn ich einen von einer API übergeben bekomme.
- See previous answers
- Weitere Antworten anzeigen