Designated Initializer
一个类,可能有很多初始化函数,但是有主次之分,最主要的初始函数应该对类内应当需要初始化的变量进行初始化。这个最主要的初始函数即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的更多相关文章
- iOS: 聊聊 Designated Initializer(指定初始化函数)
iOS: 聊聊 Designated Initializer(指定初始化函数) 一.iOS的对象创建和初始化 iOS 中对象创建是分两步完成: 分配内存 初始化对象的成员变量 我们最熟悉的创建NSOb ...
- ios 修正waring:Method override for the designated initializer of the superclass '-init' not found
swift引入后,为了使oc和swift更相近,对oc的初始化方法也进行了修正,具体说明,见下面的链接,这个waring的最简单的修正方法是,到相应类的头文件中,去掉在自定义初始化方法后面的 NS_D ...
- 正确编写Designated Initializer的几个原则
Designated Initializer(指定初始化器)在Objective-C里面是很重要的概念,但是在日常开发中我们往往会忽视它的重要性,以至于我们写出的代码具有潜藏的Bug,且不易发现.保证 ...
- designated initializer和secondary initializer是什么?
仅在此简单记录概念,方便以后回顾... ===================================== designated initializer是指定初始化方法,提供所有参数: sec ...
- iOS: Designated Initializer(指定初始化函数)
偶然间看到“ Designated Initializer”一词,心里一惊,这是什么东西,怎么没听说过?难道是我道行太浅?真的是这样?(好伤心啊)一阵子我怀疑之后,果断上网查了一下这个 Designa ...
- iOS: 聊聊 Designated Initializer(指定初始化函数):NS_DESIGNATED_INITIALIZER
总结:指定函数的调用规则: 初始化函数的调用顺序与初始化顺序相反. 上面关于指定初始化的规则讲了那么多,其实可以归纳为两点: 便利初始化函数只能调用自己类中的其他初始化方法 指定初始化函数才有资格调用 ...
- 【swift】CoreData Crash(崩溃)(Failed to call designated initializer on NSManagedObject class)
感谢另一篇博客:https://blog.csdn.net/devday/article/details/6577985 里面的图片和介绍,发现问题如他描述的一样,没有bundle 我的Xcode版本 ...
- swift语言点评十七-Designated Initializers and Convenience Initializers
Swift defines two kinds of initializers for class types to help ensure all stored properties receive ...
- iOS 方法修饰符
一.NS_DESIGNATED_INITIALIZER 用来修饰init方法,被修饰的方法称为designated initializer:没有被这个修饰的init方法称为convenience i ...
随机推荐
- js 不固定传参
js 不固定传参 CreationTime--2018年7月2日15点18分 Author:Marydon /** * 声明一个函数 * @explain 传参个数不确定 */ function ...
- chrome 禁止自动更新
禁止chrome自动更新 CreateTime--2017年7月4日09:07:01Author:Marydon 版本号:59.0.3071.115 x64 第一步:禁止Google更新服务 参考 ...
- oracle 对系统日期sysdate进行格式化:to_date(sysdate,'yyyy-MM-dd')
oracle 对系统日期sysdate进行格式化:to_date(sysdate,'yyyy-MM-dd') CreateTime--2018年5月17日10:11:34 Author:Maryd ...
- 图片压缩兼修改md5
概述 一个桌面程序,能修改图片的尺寸和质量,并且通过加水印的方式修改图片的md5等值. 详细 代码下载:http://www.demodashi.com/demo/13498.html 一.程序截图 ...
- Column count of mysql.user is wrong. Expected 43, found 42. Created with MySQL 50518, now running 50641. Please use mysql_upgrade to fix this error.
出现问题: Column count of mysql.user is wrong. Expected 43, found 42. Created with MySQL 50518, now runn ...
- HTML5 学习笔记 应用程序缓存
使用html5 通过创建cache manifest文件,可以轻松地创建web应用的离线版本. html5引入了应用程序缓存,这意味着web应用可进行缓存,并可在没有因特网连接时进行访问. 应用程序缓 ...
- [Asp.Net]最近一个项目的总结
引言 项目到目前告一段落,目前进入测试阶段,下周就要去部署了.虽然项目不大,但是从头到尾都是自己一个人负责,在完成编码之后,对代码进行走查,命名规范,业务逻辑,代码优化等,能负责一个项目的整个编码,非 ...
- 如何修改浏览器默认的alert样式?
window.alert = function(str) { var shield = document.createElement("DIV"); shield.id = &qu ...
- vim插件管理利器
一.pathogen简介 通常情况下安装vim插件,通常是将所有的插件和相关的doc文件都安装在中一文件夹中,如将插件全部安装在/usr/share/vim/vim73/plugin/目录下,将帮助文 ...
- 进程控制函数(3)-getsid()和setsid()获取当前会话和建立新会话
pid_t setsid(void) 1.调用进程不能是进程组组长,该进程变成新会话首进程(session header) 2.该进程成为一个新进程组的组长进程. 3.需有root权限(ubuntu不 ...