在objective-c/cocoa中抛出异常的最佳方法是什么?


当前回答

可以使用两种方法在try catch块中引发异常

@throw[NSException exceptionWithName];

或者第二种方法

NSException e;
[e raise];

其他回答

我使用[NSException raise:format:]如下所示:

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

自从ObjC 2.0以来,Objective-C异常不再是C的setjmp() longjmp()的包装器,并且与c++异常兼容,@try是“免费的”,但抛出和捕获异常的代价要高得多。

无论如何,断言(使用NSAssert和NSCAssert宏家族)抛出NSException,这是明智的使用它们作为Ries状态。

@throw([NSException exceptionWith…])

Xcode将@throw语句识别为函数出口点,就像return语句一样。使用@throw语法可以避免错误的“Control may reach end of non-void function”警告,你可能会从[NSException raise:…]得到这种警告。

同样,@throw也可以用来抛出不属于NSException类的对象。

There is no reason not to use exceptions normally in objective C even to signify business rule exceptions. Apple can say use NSError who cares. Obj C has been around a long time and at one time ALL C++ documentation said the same thing. The reason it doesnt matter how expensive throwing and catching an exception is, is the lifetime of an exception is exceedingly short and...its an EXCEPTION to the normal flow. I have never heard anyone say ever in my life, man that exception took a long time to be thrown and caught.

还有,有些人认为objective C本身太昂贵,而改用C或c++编写代码。所以说总是使用NSError是无知和偏执的。

但是这篇文章的问题还没有得到回答,抛出异常的最佳方式是什么。返回NSError的方法很明显。

[NSException raise:…]@throw [[NSException alloc] initWithName.... 或者@throw [[MyCustomException…]?

我在这里使用的选中/未选中规则与上面略有不同。

checked/unchecked之间的真正区别(此处使用java隐喻)非常重要——>您是否可以从异常中恢复。所谓恢复,我指的不仅仅是不崩溃。

所以我使用@throw的自定义异常类来处理可恢复的异常,因为 它可能会有一些应用程序的方法寻找某些类型的失败在多个 @catch块。例如,如果我的应用程序是一台ATM机,我将有一个@catch块用于 “WithdrawalRequestExceedsBalanceException”。

我使用NSException:raise用于运行时异常,因为我没有办法从异常中恢复, 除了在更高的级别捕获它并记录它。而且没有必要为此创建一个自定义类。

无论如何,这就是我所做的,但如果有更好的,类似的表达方式,我也想知道。在我自己的代码,因为我停止编码C海拉很久以前,我从来没有返回一个NSError,即使我通过一个API传递一个。

@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);
}

}

使用:

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

另一个更高级的用例:

- (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

}

}