Objective-C 苹果开发文档 09 Dealing with Errors

处理程序中的错误与异常
本文探讨了在程序开发过程中如何有效地处理错误和异常,包括使用 NSError 类、委托方法、错误传递、恢复策略以及自定义错误。重点介绍了 Cocoa 和 Cocoa Touch 中错误处理的最佳实践,以及如何利用异常和 NSError 对象来提升用户体验。

Dealing with Errors

几乎所有的程序都会遇到错误。一些错误可能超出了你的控制范围,比如耗尽了内存空间或者失去了网络连接。一些错误是可以避免的,比如用户的无效输入。即使所有的开发人员都是精益求精的,程序设计员偶尔也会发生错误。

如果你之前从事的是其他的平台和语言,你可能习惯使用异常来处理大多数的错误。当你用OC编写代码时,异常仅仅用于程序员错误,比如数组边界溢出的问题或者无效的方法参数。这些问题都是在你的程序上架之前可以发现并且改正的。

其他的错误都是用NSError类表示的。本章主要介绍如何使用NSError对象,包括如何处理框架方法失败和返回错误的问题。详见Error Handling Programming Guide


Use NSError for Most Errors

在任何应用的生命周期内,错误都是不可避免的。例如,如果你需要从一个远程的web服务请求一个数据,会有各种各样的潜在问题出现,例如:

  • No network connectivity 无网络连接

  • The remote web service may be inaccessible 远程网络服务不可到达

  • The remote web service may not be able to serve the information you request 远程web服务器没有你需要的信息

  • The data you receive may not match what you were expecting 你收到的数据和你需要的不匹配

遗憾的是,你不可能制定一个应急的计划,从而解决每一个可能发生的错误。相反,你只能为错误定制出一个计划,并且知道如何处理她们,从而给出最好的用户体验。

Some Delegate Methods Alert You to Errors


如果你使用一个框架类实现一个委托对象,从而执行一个特定的任务,比如从远程的web服务器下载信息,你会使用一个典型的错误处理方法。NSURLConnectionDelegate协议,包括一个connection:didFailWithError:方法:

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

如果有一个错误出现,这个代理方法会被调用,从而提供给你一个NSError对象来描述错误的问题。

一个NSError对象包括一个数字错误代码,域名和描述,以及其他的相关信息,都被打包在一个用户信息字典里。

不是为每个可能的错误都分配一个特殊的数字代码,Cocoa和Cocoa Touch中的错误被划分为许多区域。如果一个错误放生在NSURLConnection,上面的connection:didFailWithError:方法就会从NSURLErrorDomain提供一个错误。

错误对象也包含一个局部的描述,比如 “A server with the specified hostname could not be found.”(指定的主机名未被找到。)


Some Methods Pass Errors by Reference


一些Cocoa和Cocoa Touch接口会通过引用来传回错误。例如,你可能需要把一个来自远程web服务器的数据写入到磁盘中,使用NSData方法writeToURL:options:error。方法中的最后一个参数就是一个NSError的指针。

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

Before you call this method, you’ll need to create a suitable pointer so that you can pass its address:

    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指针指向一个错误对象来描述这个问题。

当通过引用来处理错误传递时,你需要测试一下方法的返回值,看看返回值是否会引发一个错误,就像上面显示的那样。不要只是测试错误指针是否被设置为指向一个错误。


Tip: 如果你对错误对象不感兴趣,只需要给error:参数传递一个NULL。

Recover if Possible or Display the Error to the User


最好的用户体验是将你的应用在一个错误中透明的恢复过来。例如,你发送了一个远程web服务器请求,如果未成功的话你可以试着再请求一次不同的服务器。这一次你可能需要对用户请求额外的数据,比如有效的用户名或者密码证书在尝试之前。

如果不能从一个错误中恢复程序,你应该警告用户。如果你为iOS使用Cocoa Touch,你需要创建安装一个UIAlertView用来显示错误。如果你为OS X使用Cocoa,你需要调用presentError:为任何NSResponder对象(比如一个视图,窗口或者程序对象自己本身),错误会向上传递相应器链条,为了更深层次的配置或者恢复。当她到达应用对象的时候,应用会通过一个警示面板显示错误给用户。

For more information on presenting errors to the user, see Displaying Information From Error Objects.

Generating Your Own Errors

In order to create your own NSError objects you’ll need to define your own error domain, which should be of the form:

为了创建你自己的NSError对象,你需要定义你自己的错误域,形式如下:

com.companyName.appOrFrameworkName.ErrorDomain

You’ll also need to pick a unique error code for each error that may occur in your domain, along with a suitable description, which is stored in the user info dictionary for the error, like this:

你需要为每个在你的错误域中可能发生的每个错误挑选一个特别的错误代码,同时需要一个合适的描述,描述存储在用户信息字典里,像这样:

    NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
    NSString *desc = NSLocalizedString(@"Unable to…", @"");
    NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
 
    NSError *error = [NSError errorWithDomain:domain
                                         code:-101
                                     userInfo:userInfo];

This example uses the NSLocalizedString function to look up a localized version of the error description from a Localizable.strings file, as described in Localizing String Resources.

If you need to pass back an error by reference as described earlier, your method signature should include a parameter for a pointer to a pointer to an NSError object. You should also use the return value to indicate success or failure, like this:

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

If an error occurs, you should start by checking whether a non-NULL pointer was provided for the error parameter before you attempt to dereference it to set the error, before returning NO to indicate failure, like this:

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

Exceptions Are Used for Programmer Errors

OC和其他的程序语言一样也支持异常用法,类似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块代替标准的OC方法检测。在NSArray的例子中,你应该总是检查一个数组中元素的个数,以便在使用下标访问之前确定好数组的下标。如果你的使用越界,objectAtIndex:方法会抛出异常,这样你就可以提前发现错误——在你将应用展示给用户的时候,你应该避免抛出异常。

For more information on exceptions in Objective-C applications, see Exception Programming Topics.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值