当面对多个初始化方法时,外部调用者往往会手足无措,不知道哪一个才是正确的初始化方法,对此,苹果提供了两个关键字:NS_UNAVAILABLENS_DESIGNATED_INITIALIZER 来帮助我们约束定义方式,使得接口描述更加清晰。

NS_UNAVAILABLE

对于多个构造方法,它可以指定一个基础的构造方法。其它快捷的构造方法都必须通过它来实现类的初始化。代码规范的一种。可以避免不必要的bug。良好的编程习惯

对于这种能初始化全部必需变量的方法,一般可作为 designed initializer 。所以,可以明确的告诉外部调用者,无论调用哪种初始化方法,最终,都会调用 designed initializer:

一个子类如果有自己的 designed initializer,则必须要实现父类的 designed initializer。比如一个继承自 NSObject 的 Person 类,就必须要重写 init 方法,并在 init 方法中,调用自己的 designed initializer,而不是调用 super 的初始化方法。如果未实现,可以看到编译警告:

Method override for the designed initializer of the superclass ‘- init’ not found.

除此之外,子类的 designed initializer 方法,在调用 super 时,也应该调用 super 的 designed initializer。也就是说,如果 CustomView 是 UIView 的子类,那么应该写作:

在定义初始化方法时,除了能够用 NS_DESIGNATED_INITIALIZER 标记以外,还可以使用更为强势的 NS_UNAVAILABLE 。和 NS_DESIGNATED_INITIALIZER 用于明确初始化方法方式不同, NS_UNAVAILABLE 的作用是,直接禁用其他初始化方法,简单粗暴。

假设,对于 User 类,如果没有 userID 就代表着用户无效,那么我们也没必要给 init 方法一个默认的 userID = 0 ,或者 userID = nil 。此时,需要告诉调用者,就只能通过 userID 来初始化,那么可以写作:

  • (instancetype)new NS_UNAVAILABLE;
  • (instancetype)init NS_UNAVAILABLE; ///< 直接标记 init 方法不可用

  • (instancetype)initWithUserID:(NSNumber *)userID;

    方法一旦标记 NS_UNAVAILABLE ,那么在 IDE 自动补全时,就不会索引到该方法,并且如果强制调用该方法,编译器会报错(但并不代表着方法不能被调用,runtime 依然可以做到)。

    除了可以直接使用 NS_UNAVAILABLE 标记不可用以外,还有一些其他的方式:

// 作用与 NS_UNAVAILABLE 类似

  • (id) init __unavailable;

  • (id) init attribute((unavailable));

  • (id) init UNAVAILABLE_ATTRIBUTE;

    // 在调用时给出提示

  • (id) init attribute((unavailable(“Must use initWithFoo: instead.”)));

  • (instancetype)initWithUserID:(NSNumber *)userID {
    self = [super init];
    if (self) {

      if (userID.integerValue <= 0) {
          // raise: 原因
          // format: 具体描述
          [NSException raise:@"error parameter" format:@"user id can not = %@", userID];
      }
      self.userID = userID;

    }
    return self;
    }

    如果是可以给出默认值初始化方法,那么使用 NS_DESIGNATED_INITIALIZER 就可以。
    如果是必须要用某参数来初始化的,可以使用 NS_UNAVAILABLE 。
    如果需要在内部验证参数是否合法,如果不合法就一定不能成功的,也可以在实现的时候,验证并抛出异常。
    具体选择使用哪一种方式,可以根据具体的情况来看。