一个类,可能有很多初始化函数,但是有主次之分,最主要的初始函数应该对类内应当需要初始化的变量进行初始化。这个最主要的初始函数即Designated Initializer(指定初始化器),可以理解为是类的默认初始函数。比如,UIView的Designated Initializer是initWithFrame:而不是init:

原则1.类的正确初始化过程应当依次调用子类到父类的Designated Initializer。即使是用父类的Designated Initializer初始化一个子类对象,也需要遵从这个过程

原则2.如果子类指定了新的Designated Initializer,那么该函数必须调用父类的Designated Initializer。并且需要重写父类的Designated Initializer,将其指向子类新的Designated Initializer

NSObject的Designated Initializer为init;
UIView的Designated Initializer为initWithFrame:;
TestView继承于UIView,它有一个属性Name,所以它的Designated Initializer为initWithFrame:andName:

假如不遵循第2点,initWithFrame:andName:的实现如下

- (id)initWithFrame:(CGRect)frame andName:(NSString *)name
{
if (self = [super init])
{
self.name = name;
}
return self;
}

测试1:使用子类的Designated Initializer初始化子类对象

TestView *testView = [[TestView alloc] initWithFrame:CGRectZero andName:@""];

调用顺序如下:
1)TestView的initWithFrame:andName:
2)UIView的init
3)UIView的initWithFrame
4)NSObject的init
此时没问题,3个类的Designated Initializer都被调用了

测试2:使用父类的Designated Initializer初始化子类对象

TestView *testView = [[TestView alloc] initWithFrame:CGRectZero];

调用顺序如下:
1)UIView的initWithFrame
2)NSObject的init
此时有问题,TestView的Designated Initializer没有被调用

而测试1之所以没问题,是因为UIView遵循了原则1和原则2。

好,现在我们将TestView修改为遵循原则1和原则2。

- (id)initWithFrame:(CGRect)frame andName:(NSString *)name
{
if (self = [super initWithFrame:frame])
{
self.name = name;
}
return self;
} - (id)initWithFrame:(CGRect)frame
{
return [self initWithFrame:frame andName:@""];
}

测试1:使用子类的Designated Initializer初始化子类对象

TestView *testView = [[TestView alloc] initWithFrame:CGRectZero andName:@""];

调用顺序如下:
1)TestView的initWithFrame:andName:
2)UIView的initWithFrame
3)NSObject的init
此时没问题,3个类的Designated Initializer都被调用了

测试2:使用父类的Designated Initializer初始化子类对象

TestView *testView = [[TestView alloc] initWithFrame:CGRectZero];

调用顺序如下:
1)TestView的initWithFrame
2)TestView的initWithFrame:andName:
3)UIView的initWithFrame
4)NSObject的init
此时没问题,3个类的Designated Initializer都被调用了

原则3.你可以不自定义Designated Initializer,但需要通过重写父类的Designated Initializer,来调用父类的Designated Initialzier

- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame])
{
self.name = name; //注意这里的name不是通过初始化函数传递进来的
}
return self;
}

原则4.如果有多个Secondary Initializers(次要初始化器),它们之间可以任意调用,但最后必须指向该类的Designated Initializer。而且在Secondary Initializer内不能直接调用父类的初始化器。注意重写父类的Designated Initializer的也算是Secondary Initializer

//Super Override
- (id)initWithFrame:(CGRect)frame
{
return [self initWithFrame:frame andName:@""];
} //Designated Initializer
- (id)initWithFrame:(CGRect)frame andName:(NSString *)name
{
if (self = [super initWithFrame:frame])
{
self.name=name;
}
return self;
} //Instance Secondary Initializer
- (id)initWithName:(NSString *)name
{
return [self initWithFrame:CGRectZero andName:name];
} //Instance Secondary Initializer
- (id)initWithName2:(NSString *)name
{
return [self initWithName:name];
} //Class secondary initializer
+ (id)testViewWithName:(NSString *)name
{
TestView *testView=[[TestView alloc] initWithFrame:CGRectZero andName:name];
return testView;
}

可以看到方法initWithName2调用的顺序是initWithName2–>initWithName–>initWithFrame:andName:,最后指向了Designated Initializer。
同时需要注意的是,Secondary initializers不仅可以是实例方法,也可以是静态方法,如testViewWithName:

还有一个问题是为什么Secondary Initializer内不能直接调用父类的初始化器?
我们要明确,调用父类的Designated Initializer的那个方法就是子类的Designated Initializer,Designated Initializer有且只有1个,所以即使有多个初始化函数,也要保证只能有一个是Designated Initializer

P.S.

使用 NS_DESIGNATED_INITIALIZER 来显式指定 Designated Initializer,参照《Adopting Modern Objective-C》

- (instancetype)init NS_DESIGNATED_INITIALIZER;

参考链接

正确编写Designated Initializer的几个原则

Designated Initializer的更多相关文章

  1. iOS: 聊聊 Designated Initializer(指定初始化函数)

    iOS: 聊聊 Designated Initializer(指定初始化函数) 一.iOS的对象创建和初始化 iOS 中对象创建是分两步完成: 分配内存 初始化对象的成员变量 我们最熟悉的创建NSOb ...

  2. ios 修正waring:Method override for the designated initializer of the superclass '-init' not found

    swift引入后,为了使oc和swift更相近,对oc的初始化方法也进行了修正,具体说明,见下面的链接,这个waring的最简单的修正方法是,到相应类的头文件中,去掉在自定义初始化方法后面的 NS_D ...

  3. 正确编写Designated Initializer的几个原则

    Designated Initializer(指定初始化器)在Objective-C里面是很重要的概念,但是在日常开发中我们往往会忽视它的重要性,以至于我们写出的代码具有潜藏的Bug,且不易发现.保证 ...

  4. designated initializer和secondary initializer是什么?

    仅在此简单记录概念,方便以后回顾... ===================================== designated initializer是指定初始化方法,提供所有参数: sec ...

  5. iOS: Designated Initializer(指定初始化函数)

    偶然间看到“ Designated Initializer”一词,心里一惊,这是什么东西,怎么没听说过?难道是我道行太浅?真的是这样?(好伤心啊)一阵子我怀疑之后,果断上网查了一下这个 Designa ...

  6. iOS: 聊聊 Designated Initializer(指定初始化函数):NS_DESIGNATED_INITIALIZER

    总结:指定函数的调用规则: 初始化函数的调用顺序与初始化顺序相反. 上面关于指定初始化的规则讲了那么多,其实可以归纳为两点: 便利初始化函数只能调用自己类中的其他初始化方法 指定初始化函数才有资格调用 ...

  7. 【swift】CoreData Crash(崩溃)(Failed to call designated initializer on NSManagedObject class)

    感谢另一篇博客:https://blog.csdn.net/devday/article/details/6577985 里面的图片和介绍,发现问题如他描述的一样,没有bundle 我的Xcode版本 ...

  8. swift语言点评十七-Designated Initializers and Convenience Initializers

    Swift defines two kinds of initializers for class types to help ensure all stored properties receive ...

  9. iOS 方法修饰符

     一.NS_DESIGNATED_INITIALIZER 用来修饰init方法,被修饰的方法称为designated initializer:没有被这个修饰的init方法称为convenience i ...

随机推荐

  1. JSP,PHP,Python,Ruby,Perl概要及各自特点

    JSP,PHP,Python,Ruby,Perl概要及各自特点 博客分类: JSP PHP Python Ruby Perl概要及各自特点 javascript  互联网技术日新月异,编程的语言层出不 ...

  2. C++ bool和string转换

    直接贴代码吧.用g++能够编译.測试ok #include <iostream> #include <sstream> using namespace std; int mai ...

  3. c# 操作Word总结

    在医疗管理系统中为保存患者的体检和治疗记录,方便以后的医生或其他人查看.当把数据保存到数据库中,需要新建很多的字段,而且操作很繁琐,于是想到网页的信息创建到一个word文本中,在显示的时,可以在线打开 ...

  4. Cocos2d-x3.0 载入Cocostudio的UI后,button无法点击的解决方法

    原帖地址:http://blog.csdn.net/musicvs/article/details/28390617 近期发现不少朋友都遇到这个问题,用Cocostudio的UI编辑器创建好UI后,在 ...

  5. unity, Root Motion

    (引自:http://tieba.baidu.com/p/4323644080) 然后详细看了下这个文档:http://docs.unity3d.com/Manual/RootMotion.html ...

  6. setTimeout 的用法

    只有第二种和第三种是正确的用法. setTimeout(函数名, 延迟) setTimeout(show(), 1000); show() 是函数运行,这种传递方式真正传进去的是 show 函数的返回 ...

  7. 8086汇编之 CALL 和 RET指令

    Ret 和 call 也是转移指令,可是他们跟jmp不同的是,这两个转移指令都跟栈有关系. <1> ret 用栈中的数据改动IP的地址,从而实现近转移 ( ip ) = ( (ss)*16 ...

  8. Python中使用UUID

    import uuid ... ... print uuid.uuid1() 生成的方法还有uuid2..n,具体参见官网LINK,包括参数细则

  9. java中==和equals和hashcode的区别详解

    一.相同点 都是用来进行值或对象的比较. 二.不同点 对于“==”而言,对于基本类型(char,byte,short,int,long,float,double,boolean),对比的是值,所以是相 ...

  10. nyoj 15 括号匹配(2)

    括号匹配(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:6 描述 给你一个字符串,里面只包含"(",")","[" ...