处理错误(Dealing with Errors)

如果你来自其他平台和语言,你可能习惯于处理大多数错误处理的异常。当你使用Objective-C写代码,异常仅仅用于程序员错误,像数组访问越界或者非法的方法参数。这些都是你应该在应用发布前在测试中发现并修改的问题。

所有的错误都是用NSError类的实例表示。这个章节给出使用NSError对象的一个简短的介绍,包括如何使用可能失败并返回错误的框架方法。进一步的信息,请查看Error Handling Programming Guide

为大部分错误使用NSError

可悲的是,为每一个可能的问题制定应急计划和解决方案是不可能的。相反,你必须计划错误,并知道如何处理它们以提供最佳的用户体验。

某些委托方法会警告你错误

如果你为了使用一个执行特定任务的框架类正在实现一个委托对象,像从远程服务器下载信息,你通常会发现你需要实现至少一个错误相关的方法。例如,NSURLConnectionDelegate协议,包含一个connection:didFailWithError:方法:

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;

如果一个错误产生,这个委托方法会被调用以提供一个描述问题的NSError对象。

NSError对象包括数字错误码,域和说明,还有打包在用户信息字典中的其他相关信息。

Cocoa和Cocoa Touch错误分以不同的域做区分,而不是要求每一个可能的错误都有一个唯一的数字码。例如,如果NSURLConnection中发生一个错误,上面的connection:didFailWithError:方法将从NSURLErrorDomain中提供错误。

错误对象也包括一个本地化的描述,比如“找不到指定主机名的服务器”。

一些方法通过引用传递错误

一些Cocoa和Cocoa Touch API通过引用传回错误。例如,你可能会决定使用NSData方法writeToURL:options:error:写入的方式,将从服务器接收的数据存储到磁盘。这个方法的最后一个参数是一个NSError指针的引用:

- (BOOL)writeToURL:(NSURL *)aURL
           options:(NSDataWritingOptions)mask
             error:(NSError **)errorPtr;

调用这个方法之前,你需要创建一个合适的指针以传递它的地址:

    NSError *anyError;
    BOOL success = [receivedData writeToURL:someLocalFileURL
                                    options:0
                                      error:&anyError];
    if (!success) {
        NSLog(@"Write failed with error: %@", anyError);
        // present error to user
    }

如果出错,writeToURL:...方法将返回NO,并更新你的anyError指针指向一个描述问题的错误对象。

处理通过引用传递的错误时,重要的是要像上面一样测试方法的返回值看是否有错误发生。不要仅仅去看是否错误指针被设置指向了一个错误。

提示:如果你不关心错误对象,error:参数传NULL就好。

如果可能就恢复,或者向用户显示错误

生成你自己的错误

创建你自己的NSError对象,你需要定义你自己的错误域,应该是这样的形式:

com.companyName.appOrFrameworkName.ErrorDomain

你也需要为你的域中产生的每一个错误选一个唯一的错误码,还有一个需要存储在用户信息字典中的合适的描述,如下所示:

    NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
    NSString *desc = NSLocalizedString(@"Unable to…", @"");
    NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };

    NSError *error = [NSError errorWithDomain:domain
                                         code:-101
                                     userInfo:userInfo];

这个例子使用NSLocalizedString函数从Localizable.strings文件中查询错误描述的本地化版本,如本地化字符串资源中所描述。

如果你需要像前面描述的一样通过引用传回一个错误,你的方法签名需要包含一个指向指向NSError对象的指针的参数。你也需要使用返回值表明成功或失败,如下所示:

- (BOOL)doSomethingThatMayGenerateAnError:(NSError **)errorPtr;

如果一个错误产生,返回表示失败的NO之前,你需要先检查为错误参数提供的是否是一个非空的指针,然后尝试街引用它以设置错误,如下所示:

- (BOOL)doSomethingThatMayGenerateAnError:(NSError **)errorPtr {
    ...
    // error occurred
    if (errorPtr) {
        *errorPtr = [NSError errorWithDomain:...
                                        code:...
                                    userInfo:...];
    }
    return NO;
}

异常被用于程序员错误

Objective-C支持与其他编程语言非常相似的异常,跟Java或C++的语法很像。像NSError一样,异常在Cocoa和Cocoa Touch中也是对象,用NSException类的对象表示。

如果你需要写一段可能会引发异常的代码,你可以把代码放在try-catch块中:

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

如果@try块中的代码抛出了一个异常,它将被@catch块捕获以便于你可以处理它。例如,若干你在使用底层的C++库时使用异常做错误处理,你可以捕获异常然后创建合适的NSError对象展示给用户。

如果一个异常抛出且没被捕获,默认的未捕获异常处理程序会在控制台打印日志并终止应用程序。

你不应该使用try-catch块代替Objective-C方法的标准编程检查。例如,NSArray的情况,你应该总是在获取一个给定下标的对象之前检查数组的count来决定元素的个数。如果你发起一个越界请求,objectAtIndex:方法会抛出一个异常,这样你就可以在开发周期的早期发现代码中的bug,你应该避免在发布给用户的应用程序中抛出异常。

更多关于Objective-C应用程序的异常信息,请看Exception Programming Topics

results matching ""

    No results matching ""