当前位置:K88软件开发文章中心编程语言Objective-CObjective-C01 → 文章内容

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-10 11:12:17

s designated initializer self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) { // Custom initialization {
return self;
{
@end在 UIViewController 子类的例子里面如果重载 init 会是一个错误,
这个情况下调用者会尝试调用 initWithNib:bundle 初始化你的类,
你的类实现不会被调用。
着同样违背了它应该是合法调用任何 designated initializer 的规则。
在你希望提供你自己的初始化函数的时候,
你应该遵守这三个步骤来保证正确的性:定义你的 designated initializer,
确保调用了直接超类的 designated initializer重载直接超类的 designated initializer。
调用你的新的 designated initializer.为新的 designated initializer 写文档很多开发者忽略了后两步,
这不仅仅是一个粗心的问题,
而且这样违反了框架的规则,
而且可能导致不确定的行为和bug。
让我们看看正确的实现的例子:@implementation ZOCNewsViewController- (id)initWithNews:(ZOCNews *)news{ // call to the immediate superclass'
s designated initializer self = [super initWithNibName:nil bundle:nil];
if (self) { _news = news;
{
return self;
{
// Override the immediate superclass'
s designated initializer (重载直接父类的 designated initializer)- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{ // call the new designated initializer return [self initWithNews:nil];
{
@end你没重载 initWithNibName:bundle: 而且调用者决定用这个方法初始化你的类(这是完全合法的)。
initWithNews: 永远不会被调用,
所以导致了不正确的初始化流程,
你的类特定的初始化逻辑没有被执行。
即使可以推断那个方法是 designate initializer它,
但是最好清晰地明确(未来的你或者其他开发者在改代码的时候会感谢你的)。
你应该考虑来用这两个策略(不是互斥的):第一个是你在文档中明确哪一个初始化方法是 designated 的,
但是最好你可以用编译器的指令 __attribute__((objc_designated_initializer)) 来标记你的意图。
用这个编译指令的时候,
编译器回来帮你。
如果你的新的 designate initializer 没有调用你超类的 designated initializer,
上编译器会发出警告。
然而,
当没有调用类的 designated initializer 的时候(并且依次提供必要的参数),
并且调用其他父类中的 designated initialize 的时候,
会变成一个不可用的状态。
参考之前的例子,
当实例化一个 ZOCNewsViewController 展示一个新闻而那条新闻没有展示的话,
就会毫无意义。
这个情况下你应该只需要让其他的 designated initializer 失效,
来强制调用一个非常特别的 designated initializer。
通过使用另外一个编译器指令 __attribute__((unavailable("Invoke the designated initializer"))) 来修饰一个方法,
通过这个属性,
会让你在试图调用这个方法的时候产生一个编译错误。
这是之前的例子相关的实现的头文件(这里使用宏来让代码没有那么啰嗦)@interface ZOCNewsViewController : UIViewController- (instancetype)initWithNews:(ZOCNews *)news ZOC_DESIGNATED_INITIALIZER;
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil ZOC_UNAVAILABLE_INSTEAD(initWithNews:);
- (instancetype)init ZOC_UNAVAILABLE_INSTEAD(initWithNews:);
@end上述的一个推论是:你应该永远不从 designated initializer 里面调用一个 secondary initializer (如果secondary initializer 遵守约定,
它会调用 designated initializer)。
如果这样,
调用很可能会调用一个子类重写的 init 方法并且陷入无限递归之中。
然而一个意外是一个对象是否遵守 NSCoding 协议,
并且它通过方法 initWithCoder: 初始化。
我们应该区别超类是否符合 NSCoding 的情况。
如果符合,
如果你只是调用 [super initWithCoder:] 你会可能有一个共享的初始化代码在 designated initializer 里面,
一个好的方法是吧这些代码放在私有方法里面(比如 p_commonInit )。
当你的超类不符合NSCoding 协议的时候,
推荐把 initWithCoder: 作为 secondary initializer 来对待,
并且调用 self 的 designated initializer。
注意这是违反 Apple 的 Archives and Serializations Programming Guide 上面写的:the object should first invoke its superclass'
s designated initializer to initialize inherited state (对象总是应该首先调用超类的 designated initializer 来初始化继承的状态)如果你的类不是 NSObject 的直接子类,
这样做的话,
会导致不可预测的行为。
Secondary Initializer正如之前的描述么,
secondary initializer 是一种方便提供默认值、行为到 designated initializer 的 方法。
也就是说,
你不应该强制很多初始化操作在这样的方法里面,
并且你应该一直假设这个方法不会得到调用。
我们保证的是唯一被调用的方法是 designated initializer。
这意味着你的 designated initializer 总是应该调用其他的 secondary initializer 或者你 self 的 designated initializer。
有时候,
因为错误,
可能打成了 super,
这样会导致不符合上面提及的初始化顺序(在这个特别的例子里面,
是跳过当前类的初始化)References 参考https://developer.apple.com/library/ios/Documentation/General/Conceptual/DevPedia-CocoaCore/ObjectCreation.htmlhttps://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/Initialization/Initialization.htmlhttps://developer.apple.com/library/ios/Documentation/General/Conceptual/DevPedia-CocoaCore/MultipleInitializers.htmlhttps://blog.twitter.com/2014/how-to-objective-c-initializer-patternsinstancetype我们经常忽略 Cocoa 充满了约定,
并且这些约定可以帮助编译器变得更加聪明。
无论编译器是否遭遇 alloc 或者 init 方法,
他会知道,
即使返回类型都是 id ,
这些方法总是返回接受到的类类型的实例。
因此,
它允许编译器进行类型检查。
(比如,
检查方

上一页  [1] [2] [3] [4] [5]  下一页