一个类,可能有很多初始化函数,但是有主次之分,最主要的初始函数应该对类内应当需要初始化的变量进行初始化。这个最主要的初始函数即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. Qt 5.3更新无数,更改C++控制台输出最为赞

    迁移至 多色网

  2. Python爬虫实战案例:爬取爱奇艺VIP视频

    一.实战背景 爱奇艺的VIP视频只有会员能看,普通用户只能看前6分钟.比如加勒比海盗5的URL:http://www.iqiyi.com/v_19rr7qhfg0.html#vfrm=19-9-0-1 ...

  3. jquery tmpl 详解(转)

    动态请求数据来更新页面是现在非常常用的方法,比如博客评论的分页动态加载,微博的滚动加载和定时请求加载等. 这些情况下,动态请求返回的数据一般不是已拼好的 HTML 就是 JSON 或 XML,总之不在 ...

  4. javascript 打印错误信息 catch err

    使用 console.log(err); 是无法打印出来的.默认只能打印出错误信息.如图 http.interceptors.response.use(response => { return ...

  5. mybatis-spring 项目简介

    mybatis-spring 主要是为了解决 spring3.0 中支持 mybatis3.0 1 mybatis-spring 主要包含以下几个部分 数据源 SqlSessionFactory Sq ...

  6. js方式实现页面加遮罩效果

    有时候在页面上执行查询的时候由于数据量很大,需要较长时间,所以就需要在等待结果期间不可以操作页面,那么可以使用如下代码给页面添加遮罩效果: $.messager.progress({ title: ' ...

  7. PHP is_callable 方法

    is_callable (PHP 4 >= 4.0.6, PHP 5) is_callable — 验证变量的内容是否能够进行函数调用 Description bool is_callable  ...

  8. Lattice 开发工具Diamond 相关版本下载地址

    百度网盘: https://wenku.baidu.com/view/21b98975192e45361066f5f3.html 官网下载: http://www.latticesemi.com/Su ...

  9. Vim-复制选中内容至系统剪贴板,光标移动到指定行的行首和行尾

    1.全选并复制到系统剪贴板 ggVG或ggvG 然后 "+y gg 让光标移到首行,在vim才有效,vi中无效 V 是进入Visual(可视)模式 G 光标移到最后一行 "+y 复 ...

  10. CGameMainScene类

    #ifndef __GAMEMAIN_SCENE_H__ #define __GAMEMAIN_SCENE_H__ #include "cocos2d.h" #include &q ...