NSError 最佳实践

访问系统的一些资源的时候,不可避免的会遇到一些错误,我们需要告诉用户或者提醒我们自己遇到什么问题了,方便定位解决。比如移除指定路径文件或者目录的时候,可能文件不存在或者路径有问题等等,我们需要知道究竟为什么不能成功移除,这时候错误信息就很重要了,看下系统是怎么设计这类 API 的。- (BOOL)removeItemAtPath:(NSString *)path error:(NSError * _Nullable *)error;

使用类似 API 的时候通常都是传递 NSError * _Nullable * 这种参数,目的是为了延长 error 的初始化时机,让 error 在执行任务的时候再初始化并赋予错误信息。

NSError 里面包含的信息很丰富。主要是三个,domain,code 和错误相关的信息。code 是和 domain 相关的。

一个 NSError 的最佳实践是是使用倒序域名方式,这样可以有效避免 NSError 的域名重复。然后根据倒序域名定义错误 code,域名不重复的话,这些 code 可以随意定制,是不会和别的域名下的 code 冲突的。具体看下面 demo

static NSString *const kUserInfoDomain = @"com.app.userinfo";

typedef enum : NSUInteger {
    AUIUserNotExist = 0,
    AUIUserNameEmpty,
} AUIErrorCode;

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self fetchUserInfoWithError:&error];
}

- (NSString *)fetchUserInfoWithError:(NSError **)error {
    NSDictionary *errInfo =@{NSLocalizedDescriptionKey:@"用户不存在"};
    - (void)btnPressed:(id)sender {
    NSError *error = nil;
    [self fetchUserInfoWithError:error];
    NSLog(@"error = %@",error);
}
//模拟一次错误获取
- (NSString *)fetchUserInfoWithError:(NSError **)error {
    NSDictionary *errInfo = @{NSLocalizedDescriptionKey:@"用户不存在"};
    if(error != NULL){
        *error = [NSError errorWithDomain:kUserInfoDomain code:AUIUserNotExist userInfo:errInfo];
    }
    return nil;
}

以上错误处理代码中需要注意的一点就是 error 的判断 if(error != NULL) 加这一行的作用是区分一下两种调用方式

  1. [self fetchUserInfoWithError:nil];
  2. NSError *error = nil; [self fetchUserInfoWithError:error];

如果是像前者一样调用的话,是不会走进这个 if(error != NULL)分支判断,我们没必要为这种情况单独初始化一个 error 实例。

以上,在帮别的同事封装可调用 API 的时候增加必要的 NSError 参数,不仅方便别人,其实也是方便自己。

# 参考

NSError (opens new window) Best Practice - NSError domains and codes for your own project/app (opens new window)