21、理解Objective-C错误模型

Error对象里封装了三条信息:

  • Error domain:错误范围,字符串

    产生错误的根源,通常用一个特有的全局变量来定义。如:NSURLError表示解析URL出错

  • Error code:错误码,整数

    独有的错误码,指明在某个范围内具体发生了何种错误,通常用enum定义。如:HTTP请求出错时,可能回把HTTP的状态码设为错误码

  • User info:用户信息,字典

    有关此错误的额外信息,其中或许包含一段“本地化的描述”(localized description),或许还含有导致该错误发生的另外一个错误,经由此种信息,可将相关错误串成一条“错误链”(chain of errors)

  • 通过“委托协议”传递错误

    有错误放生时,当前对象会把错误信息经由协议中的某个方法传递给其delegate委托对象,如:

    ​ 当NSURLConnection出错后(比如与远程服务器的链接操作超时了),就回调用此方法以处理相关错误:

    - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
      DDLogDebug(@"connection didFailWithError %@", error);
    }

    ​ 这个委托方法未必非得实现不可:是不是必须处理此错误,可交由NSURLConnection类的用户来判断。(这比抛出异常要好,因为调用者至少可以自己决定是否需要处理该错误)

  • 通过方法的“输出参数”传递错误

    如:

    // 传入的是一个指针的内存地址(因为change的是:指针重指向,而不是修改指向的内容)
    - (BOOL)doSomething:(NSError **)error {
      if (/* 有错误*/) {
        if (error) { // 必须判断 
          // *error: 为error参数“解引用”(dereference),及error所指的那个指针现在要指向一个新的NSError对象了。
          *error = [NSError errorWithDomain:domain code:code userInfor:dic];
          // 在解引用之前必须保证error参数不是nil
          // 因为空指针解引用会导致carsh:“段错误”segmentation fault
        }
      }
    }
    // 使用:
    // 1.在乎error
    NSError *error = nil;
    BOOL result = [object doSomething:&error];
    if (error) {
      // 处理error
    }
    // 2.不在乎error
    BOOL result = [object doSomething:nil];
    if (!result) {
        // 处理error
    }

    像这样的方法一般返回Boolean值,表示该操作成功 or 失败。如果调用者不关注估计的错误信息,则直接判断该Boolean值就好了;若关注具体错误,那就检查经由“输出参数”所返回的那个错误对象。

​ NSError的domain、code、userInfor应该根据具体错误情况填入适当内容,方便调用者根据错误类型分别处理各错误。domain定义成NSString类型的全局常量,而code则定义成枚举类型为佳。如:

// XXXErrors.h
extern NSString *const XXXErrorDomain;
typedef NS_ENUM(NSUInteger, XXXError) {
  XXXErrorUnKnown             = -1,
  XXXErrorGeneralFault    = 100,
  XXXErrorBadInput            = 101,
}
// XXXErrors.m
NSString *const XXXErrorDomain = @"XXXErrorDomain";

建议:

  • 为自己的程序库中所发生的错误制定一个专用的“错误范围”字符串

  • 用枚举定义错误码,不仅解释错误码的含义,还给它们起了个有意义的名字

要点:

  • 只有发生了会使整个应用程序崩溃的严重错误时,才使用异常

  • 在错误不那么严重的情况下,可以指派“委托方法”(delegate method)来处理错误,也可以把错误信息放在NSError对象里,经由“输出参数”返回给调用者

Last updated

Was this helpful?