在Objective-C中,异常/返回NO / nil的最佳实践是什么?

时间:2011-07-23 17:28:32

标签: objective-c exception exception-handling return-value

我是Objective-C的新手,我发现有关于错误处理的不同约定。有一些例外,但也有一些情况,如果出现问题,函数应该返回nil。

那么,我如何决定何时使用哪个,以及如何处理异常和意外的返回值?什么是最佳做法和危险信号?

4 个答案:

答案 0 :(得分:35)

我不会确定使用哪个,但这里有关于每个选项的一些信息:

例外

Obj-C中的异常并不真正用于控制程序流程。来自documentation on exception handling

  

一般模式是异常仅为程序员错误保留,并且捕获此类异常的程序应该很快就会退出。

出于这个原因,我不建议仅使用例外@try / @catch来测试方法是否正常工作。

除了设置更高级several options for handling exceptions之外,您还有uncaught exception handler

错误

错误通常以三种方式使用:

委托方法

对象可以在指定的错误处理回调函数中将NSError简单地传递给其委托:

- (void)myObject:(MyObject *)obj didFailWithError:(NSError *)error;
然后,代表可以自由采取任何适当的行动,包括可能向用户显示消息。此模式通常用于基于异步委托的API。

输出参数

这些最常用于布尔返回值:如果返回值为NO,则可以检查NSError对象以获取有关错误的更多信息。

- (BOOL)performTaskWithParameter:(id)param returningError:(out NSError **)error;

一种可能的使用模式是:

NSError *error;
if (![myObject performTaskWithParameter:@"param" returningError:&error]) {
    NSLog(@"Task failed with error: %@", error);
}

(有些人还喜欢在检查之前将布尔结果存储在变量中,例如BOOL success = [myObject perform...];。)由于此模式的线性特性,它最适合用于同步任务。

基于块的完成处理程序

自引入块以来的一个相当新的模式,但是非常有用的模式:

- (void)performAsynchronousTaskWithCompletionHandler:(void (^)(BOOL success, NSError *error))handler;

像这样使用:

[myObject performAsynchronousTaskWithCompletionHandler:^(BOOL success, NSError *error) {
    if (!success) {
        // ...
    }
}];

这变化很大:有时你不会看到布尔参数,只看错误;有时处理程序块没有传递给它的参数,你只需检查对象的状态属性(例如,这就是AVAssetExportSession的工作原理)。当您需要基于块的方法时,此模式对于异步任务也很有用。

处理错误

Mac OS X上的Cocoa有一个quite thorough error-handling path。还有NSAlert的便捷方法+ (NSAlert *)alertWithError:(NSError *)error;。在iOS上,NSError类仍然存在,但是没有相同的便捷方法来处理错误。你可能不得不自己做很多事情。

阅读Error Handling Programming Guide了解更多信息。

返回零

这通常与NSError out参数一起使用;例如,NSData的方法

+ (id)dataWithContentsOfFile:(NSString *)path
                     options:(NSDataReadingOptions)mask
                       error:(NSError **)errorPtr;

如果读取文件失败,此方法将返回nil,并且更多信息将存储在错误中。

这是一个特别方便的模式的一个原因是因为nil messaging,这可以安全地完成而在Obj-C中没有效果。我不会在这里详细说明为什么这是有用的,但你可以在其他地方的互联网上阅读更多关于它的内容。 (只要确保找到一篇最新的文章;它曾经是返回浮点值的方法在发送到nil时不一定会返回0,但现在它们会这样做,如文档中所述。)

答案 1 :(得分:6)

在Objective-C中应尽可能少地使用异常。在其他语言使用异常的情况下,在Objective-C中,建议大多数时候使用NSError对象。

Apple关于异常处理的文档在这里:http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/Exceptions/Exceptions.html%23//apple_ref/doc/uid/10000012il

那么如何使用NSError对象呢?好吧,如果我们查看Apple的类,使用间接指针返回错误。

例如:

- (NSObject *)objectFromSet:(NSSet *)set error:(NSError **)error 
{
    // get an object from a set; if the set has at least 1 object 
    // we return an object, otherwise an error is returned.

    NSObject *object = [set anyObject]
    if (!object) 
    {
         *error = [NSError errorWithDomain:@"AppDomain" code:1000 userInfo:nil];
         return nil;
    }

    return object;
}

// and then we use the function like this
- (void)test
{
    NSError *error = nil;
    NSSet *set = [[[NSSet alloc] init] autorelease];
    NSObject *object = [self objectFromSet:set error:&error];
    if (error) 
    {
        // handle error, perhaps show an alert view ...
    }
    else 
    {
        // use the object, all went fine ...
    }
}

答案 2 :(得分:0)

如果一个方法应该返回一个对象,并且它不能这样做,它应该返回nil。如果您要向用户报告错误,以便他们可以对其采取某种操作,请使用NSError对象。

答案 3 :(得分:0)

Objective-C支持异常的方式与其他编程语言大致相同,语法与Java或C ++类似。与NSError一样,Cocoa和Cocoa Touch中的异常是对象,由NSException类的实例表示,

您可以使用

 @try {
        // do something that might throw an exception
    }
    @catch (NSException *exception) {
        // deal with the exception
    }
    @finally {
        // optional block of clean-up code
        // executed whether or not an exception occurred
    }

详细了解错误处理apple doc