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的几个原则》
转载于:https://www.cnblogs.com/chenyg32/p/4870303.html
Designated Initializer相关推荐
- Swift Must call a designated initializer of the superclass ‘UIViewController‘
虽然很简单,也记录一下,其他类似的报错也同理. private init() {// super.init(nibName: nil, bundle: nil)super.init()} 报错提示很明 ...
- 如何设计一个 iOS 控件?(iOS 控件完全解析)
前言 一个控件从外在特征来说,主要是封装这几点: 交互方式 显示样式 数据使用 对外在特征的封装,能让我们在多种环境下达到 PM 对产品的要求,并且提到代码复用率,使维护工作保持在一个相对较小的范围内 ...
- Xcode消除编译器警告
Whenever,Xcode警告对于我们来说都相当重要,提醒我们可能存在的错误.但是有时候,我们知道一切都好,everything is in the palm of my hand,我们想要消除那些 ...
- Swift学习: 从Objective-C到Swift
作者:@方秋枋(GitHub) 这篇文章是自己学习Swift的笔记与深化.希望这篇文章能够帮助已经有Objective-C经验的开发者更快地学习Swift.同时也品味到Swift的精妙之处. 结论放在 ...
- Swift学习笔记-协议(Protocols)
1.0 翻译:geek5nan 校对:dabing1022 2.0 翻译:futantan 校对:小铁匠Linus 定稿:shanksyang 本页包含内容: 协议的语法(Protocol Synta ...
- Object C语法学习
1.OC关键字 synthesize关键字: 根据@property设置,自动生成成员变量相应的存取方法,从而可以使用点操作符来方便的存取该成员变量 . @implementation 关键字: 表明 ...
- 特定构造方法 如何让子类重写某些方法时提醒调用super
Designated initializer : 特定构造方法(方法声明后面带有NS_DESIGNATED_INITIALIZER)注意:子类如果重写了父类的特定构造方法, 那么必须使用super调用 ...
- NSThread的使用
主要用于讲解NSThread多线程的使用: 从线程创建与启动.线程的同步与锁.线程的交互.线程池等等四个方面简单的讲解一下iphone中的多线程编程: 一.线程创建与启动 线程创建主要有二种方式: - ...
- NSSet所有API学习。
/****************集合(NSSet)和数组(NSArray)有相似之处,都是存储不同的对象的地址.只是NSArray是有序的集合,NSSet是无序的集合,同一时候NSSet能够保证数据 ...
- java -c_java% c
javac不是内部或外部命令,但是java.java-version指令正常 javac不是内部或外部命令,但是java.java-version指令正常 今天遇到这个问题,云笔记博客同时Mark一下 ...
最新文章
- python是什么编程教程-python教程看完了,还是不会编程?
- Mac下配置cocos2d-x开发环境(android和ios)
- windows 生成 deploy key_推荐一个免费生成点线/方格/横线纸张的网站
- MoeCTF 2021Re部分------time2go
- 科大星云诗社动态20210412
- python文件读写_python基础-文件读写'r' 和 'rb'区别
- [BUUCTF-pwn]——jarvisoj_level302-21
- 在读博士生 2 年实现 Nature、Science 双发,他来自这所高校!
- Bex5开发平台分辨率问题解决方法
- 机器视觉中图像颜色识别理论
- 李宏毅机器学习 Regression
- 2.郝斌C语言课程大纲
- react中的this.state与this.setState的区别
- 如何安装Python?
- 好悲伤?快去MuseNet上听听Gaga风的肖邦!
- 给国外电子邮箱发海外邮件用什么邮箱好?
- 曝光更丑恶的人贩子行为!呼吁政府救救这些孩子!
- 雷声大,雨点小——《多任务下的数据结构与算法》初印象
- 自媒体淘客新手怎样做能够日入过千
- WIN10 怎么测试音响哪个是左哪个是右?
热门文章
- PowerShell install 一键部署http+用户名密码登录实现文件系统
- 量子纠缠和游戏有什么关系?道翰天琼认知智能机器人平台API接口大脑为您揭秘-1。
- 关于app定制开发的相关信息介绍
- 【翻译】ASIX AX88772C EEPROM 用户指南
- 印制电路板企业五株科技获盈科资本数千万元Pre-IPO轮投资...
- cocos2dx 看上去很美的引用计数造成的内存泄露(一)——CCCallFunc对象
- 梦幻高质织梦插件,轻松采集文章
- 极客玩物 | 新手小白家用冰箱选购指南:双十一必备攻略
- python房地产数据分析_Python3抓取 深圳房地产均价数据,通过真实数据为购置不动产做决策分析(一)...
- 几种典型的压制式干扰