加入收藏 | 设为首页 | 会员中心 | 我要投稿 52刷机网 (https://www.52shuaji.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 苹果频道 > 苹果资讯 > 正文

[iOS] NS_UNAVAILABLE 与 NS_DESIGNATED_INITIALIZER

发布时间:2017-05-18 17:30:29 所属栏目:苹果资讯 来源:www.jianshu.com
导读:原文链接:http://www.saitjr.com/ios/ios-ns_unavailable-ns_designated_initializer.html小知识点但是分析的很到位,对于此知识点不太清楚的也可以了解下。当面对多个初始化方法时,外部调用者往往会手足无措,不知道哪一个才是正确的初始化...

原文链接:http://www.saitjr.com/ios/ios-ns_unavailable-ns_designated_initializer.html小知识点但是分析的很到位,对于此知识点不太清楚的也可以了解下。当面对多个初始化方法时,外部调用者往往会手足无措,不知道哪一个才是正确的初始化...

原文链接:http://www.saitjr.com/ios/ios-ns_unavailable-ns_designated_initializer.html 小知识点但是分析的很到位,对于此知识点不太清楚的也可以了解下。

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

对于多个 init 方法,苹果给出了一个调用顺序,而我们也应该遵守这种调用顺序,以确保无论外部调用者从哪个入口进入,都能够正确的初始化:

[iOS] NS_UNAVAILABLE 与 NS_DESIGNATED_INITIALIZER
init方法调用顺序

可以看到真正在进行初始化参数的,是 initWithTitle:date: ,如果调用者通过 init 或者 initWithTitle: 进入,都应该确保变量 title 和 date 能正确赋值,所以 init 与 initWithTitle: 都通过调用 initWithTitle:date: 来初始化。最后 initWithTitle:date: 在通过父类的 init 初始化,并初始化两个变量。对于这种能初始化全部必需变量的方法,一般可作为 designed initializer 。所以,可以明确的告诉外部调用者,无论调用哪种初始化方法,最终,都会调用 designed initializer:

- (instancetype)initWithTitle:(NSString *)title date:(NSDate *)date NS_DESIGNATED_INITIALIZER;

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

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

所以,对于 Person 来说,如果 initWithName: 被标记了 NS_DESIGNED_INITIALIZER ,那么实现应该为:

- (instancetype)init {     // 在外部调用不需要 name 变量时,应该给出默认值     return [self initWithName:@"John doe"]; }  - (instancetype)initWithName:(NSString *)name {     self = [super init];     if (self) {         self.name = name;     }     return self; }

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

// 实现 UIView 的 designed initializer - (instancetype)initWithCoder:(NSCoder *)aDecoder {     return [self initWithVideoID:@0]; }  // 实现 UIView 的 designed initializer - (instancetype)initWithFrame:(CGRect)frame {     return [self initWithVideoID:@0]; }  // 实现自己的 designed initializer - (instancetype)initWithVideoID:(NSNumber *)videoID {     // 这里在调用 super 的初始化方法时,就不能调用 init,因为 init 不是 UIView 的 designed initializer     self = [super initWithFrame:CGRectZero];     if (self) {         self.videoID = videoID;         [self setupUI];     }     return self; }

NS_UNAVAILABLE

在定义初始化方法时,除了能够用 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.")));

甚至是在调用时抛出异常等,比如 userID 不能小于 0:

- (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 都能清晰的告知调用者应该如何调用方法。

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

(编辑:52刷机网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读