一个类,可能有很多初始化函数,但是有主次之分,最主要的初始函数应该对类内应当需要初始化的变量进行初始化。这个最主要的初始函数即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相关推荐

  1. Swift Must call a designated initializer of the superclass ‘UIViewController‘

    虽然很简单,也记录一下,其他类似的报错也同理. private init() {// super.init(nibName: nil, bundle: nil)super.init()} 报错提示很明 ...

  2. 如何设计一个 iOS 控件?(iOS 控件完全解析)

    前言 一个控件从外在特征来说,主要是封装这几点: 交互方式 显示样式 数据使用 对外在特征的封装,能让我们在多种环境下达到 PM 对产品的要求,并且提到代码复用率,使维护工作保持在一个相对较小的范围内 ...

  3. Xcode消除编译器警告

    Whenever,Xcode警告对于我们来说都相当重要,提醒我们可能存在的错误.但是有时候,我们知道一切都好,everything is in the palm of my hand,我们想要消除那些 ...

  4. Swift学习: 从Objective-C到Swift

    作者:@方秋枋(GitHub) 这篇文章是自己学习Swift的笔记与深化.希望这篇文章能够帮助已经有Objective-C经验的开发者更快地学习Swift.同时也品味到Swift的精妙之处. 结论放在 ...

  5. Swift学习笔记-协议(Protocols)

    1.0 翻译:geek5nan 校对:dabing1022 2.0 翻译:futantan 校对:小铁匠Linus 定稿:shanksyang 本页包含内容: 协议的语法(Protocol Synta ...

  6. Object C语法学习

    1.OC关键字 synthesize关键字: 根据@property设置,自动生成成员变量相应的存取方法,从而可以使用点操作符来方便的存取该成员变量 . @implementation 关键字: 表明 ...

  7. 特定构造方法 如何让子类重写某些方法时提醒调用super

    Designated initializer : 特定构造方法(方法声明后面带有NS_DESIGNATED_INITIALIZER)注意:子类如果重写了父类的特定构造方法, 那么必须使用super调用 ...

  8. NSThread的使用

    主要用于讲解NSThread多线程的使用: 从线程创建与启动.线程的同步与锁.线程的交互.线程池等等四个方面简单的讲解一下iphone中的多线程编程: 一.线程创建与启动 线程创建主要有二种方式: - ...

  9. NSSet所有API学习。

    /****************集合(NSSet)和数组(NSArray)有相似之处,都是存储不同的对象的地址.只是NSArray是有序的集合,NSSet是无序的集合,同一时候NSSet能够保证数据 ...

  10. java -c_java% c

    javac不是内部或外部命令,但是java.java-version指令正常 javac不是内部或外部命令,但是java.java-version指令正常 今天遇到这个问题,云笔记博客同时Mark一下 ...

最新文章

  1. python是什么编程教程-python教程看完了,还是不会编程?
  2. Mac下配置cocos2d-x开发环境(android和ios)
  3. windows 生成 deploy key_推荐一个免费生成点线/方格/横线纸张的网站
  4. MoeCTF 2021Re部分------time2go
  5. 科大星云诗社动态20210412
  6. python文件读写_python基础-文件读写'r' 和 'rb'区别
  7. [BUUCTF-pwn]——jarvisoj_level302-21
  8. 在读博士生 2 年实现 Nature、Science 双发,他来自这所高校!
  9. Bex5开发平台分辨率问题解决方法
  10. 机器视觉中图像颜色识别理论
  11. 李宏毅机器学习 Regression
  12. 2.郝斌C语言课程大纲
  13. react中的this.state与this.setState的区别
  14. 如何安装Python?
  15. 好悲伤?快去MuseNet上听听Gaga风的肖邦!
  16. 给国外电子邮箱发海外邮件用什么邮箱好?
  17. 曝光更丑恶的人贩子行为!呼吁政府救救这些孩子!
  18. 雷声大,雨点小——《多任务下的数据结构与算法》初印象
  19. 自媒体淘客新手怎样做能够日入过千
  20. WIN10 怎么测试音响哪个是左哪个是右?

热门文章

  1. PowerShell install 一键部署http+用户名密码登录实现文件系统
  2. 量子纠缠和游戏有什么关系?道翰天琼认知智能机器人平台API接口大脑为您揭秘-1。
  3. 关于app定制开发的相关信息介绍
  4. 【翻译】ASIX AX88772C EEPROM 用户指南
  5. 印制电路板企业五株科技获盈科资本数千万元Pre-IPO轮投资...
  6. cocos2dx 看上去很美的引用计数造成的内存泄露(一)——CCCallFunc对象
  7. 梦幻高质织梦插件,轻松采集文章
  8. 极客玩物 | 新手小白家用冰箱选购指南:双十一必备攻略
  9. python房地产数据分析_Python3抓取 深圳房地产均价数据,通过真实数据为购置不动产做决策分析(一)...
  10. 几种典型的压制式干扰