Swift的初始化方法
我们在深入初始化方法之前,不妨先再想想Swift中的初始化想要达到一种怎样的目的。
其实就是安全。在Objective-C中,init方法是非常不安全的:没有人能保证init只被调用一次,也没有人保证在初始化方法调用以后,实例的各个变量都完成初始化,甚至如果在初始化里使用属性进行设置的话,还可能会造成各种问题。虽然Apple也明确说明了不应该在init中使用属性来访问,但这并不是编译器强制的,因此还是会有很多开发者犯这样的错误。
所 以Swift有了超级严格的初始化方法。一方面,Swift强化了designated初始化方法的地位。Swift中不加修饰的init方法都需要在方 法中保证所有非Optional的实例变量被赋值初始化,而在子类中也强制 (显式或隐式地)调用super版本的designated初始化,所以无论如何走何种路径,被初始化的对象总是可以完成完整的初始化的。
- class ClassA {
- let numA: Int
- init(num: Int) {
- numA = num
- }
- }
- class ClassB: ClassA {
- let numB: Int
- override init(num: Int) {
- numB = num + 1
- super.init(num: num)
- }
- }
在 上面的示例代码中,注意在init里我们可以对let的实例常量进行赋值,这是初始化方法的重要特点。在Swift中let声明的值是不变量,无法被写入 赋值,这对于构建线程安全的API十分有用。而因为Swift的init只可能被调用一次,因此在init中我们可以为不变量进行赋值,而不会引起任何线 程安全的问题。
与designated初始化方法对应的是在init前加上convenience关键字的初始化方法。这类方法是 Swift初始化方法中的“二等公民”,只作为补充和提供使用上的方便。所有的convenience初始化方法都必须调用同一个类中的 designated初始化完成设置,另外convenience的初始化方法是不能被子类重写或从子类中以super的方式被调用的。
- class ClassA {
- let numA: Int
- init(num: Int) {
- numA = num
- }
- convenience init(bigNum: Bool) {
- self.init(num: bigNum ? 10000 : 1)
- }
- }
- class ClassB: ClassA {
- let numB: Int
- override init(num: Int) {
- numB = num + 1
- super.init(num: num)
- }
- }
只 要在子类中实现重写了父类convenience方法所需要的init方法的话,我们在子类中就也可以使用父类的convenience初始化方法了。比 如在上面的代码中,我们在ClassB里实现了init(num: Int)的重写。这样,即使在ClassB中没有bigNum版本的convenience init(bigNum: Bool),我们仍然还是可以用这个方法来完成子类初始化:
- let anObj = ClassB(bigNum: true)
- // anObj.numA = 10000, anObj.numB = 10001
因此进行一下总结,可以看到初始化方法永远遵循以下两个原则:
- 初始化路径必须保证对象完全初始化,这可以通过调用本类型的designated初始化方法来得到保证;
- 子类的designated初始化方法必须调用父类的designated方法,以保证父类也完成初始化。
对 于某些我们希望子类中一定实现的designated初始化方法,我们可以通过添加required关键字进行限制,强制子类对这个方法重写实现。这样的 一个最大的好处是可以保证依赖于某个designated初始化方法的convenience一直可以被使用。一个现成的例子就是上面的 init(bigNum: Bool):如果我们希望这个初始化方法对于子类一定可用,那么应当将init(num: Int)声明为必须,这样我们在子类中调用init(bigNum: Bool)时就始终能够找到一条完全初始化的路径了:
- class ClassA {
- let numA: Int
- required init(num: Int) {
- numA = num
- }
- convenience init(bigNum: Bool) {
- self.init(num: bigNum ? 10000 : 1)
- }
- }
- class ClassB: ClassA {
- let numB: Int
- required init(num: Int) {
- numB = num + 1
- super.init(num: num)
- }
- }
另外需要说明的是,其实不仅仅是对designated初始化方法,对于convenience的初始化方法,我们也可以加上required以确保子类对其进行实现。这在要求子类不直接使用父类中的convenience初始化方法时会非常有帮助。
Swift的初始化方法的更多相关文章
- Swift开发第十篇——可变参数函数&初始化方法顺序
本篇分为两部分: 一.Swift中的可变参数函数 二.初始化方法的顺序 一.Swift中的可变参数函数 可变参数函数指的是可以接受任意多个参数的函数,在 OC 中,拼接字符串的函数就属于可变参数函数 ...
- Swift - 重写UIKit框架类的init初始化方法(以UITabBarController为例)
原来写了篇文章讲UITabBarController的用法,当时是从UIViewController跳转到UITabBarController页面,代码如下: 1 self.presentViewCo ...
- [swift]初始化方法自己主动继承
子类默认不会继承父类的初始化方法,然而,假设某种条件满足的话.父类的初始化方法还是能够继承给子类.在通常情况下,这意味着你不必复写父类的初始化方法.在安全的前提下能够以最低的代价继承父类的初始化方法. ...
- Swift - 类初始化和反初始化方法(init与deinit)
1,init():类的初始化方法(构造方法) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ...
- Mac终端使用swift REPL异常处理方法
Mac终端使用swift REPL异常处理方法 终端使用swift命令出现 warning: Swift error in module libmarisa.dylibDebug info from ...
- js jquery 页面加载初始化方法
js jquery 页面加载初始化方法 一.js页面加载初始化方法 // 1.在body里面写初始化方法. <body onload='init()'> </body> < ...
- caffe中权值初始化方法
首先说明:在caffe/include/caffe中的 filer.hpp文件中有它的源文件,如果想看,可以看看哦,反正我是不想看,代码细节吧,现在不想知道太多,有个宏观的idea就可以啦,如果想看代 ...
- oc实例变量初始化方法
1 使用实例setter方法 默认初始化方法 + setName:xxx setAge:xxx 2 使用实例功能类方法,默认初始化方法 + setName:xxx age:xxx3 使用实例初始化方法 ...
- Spring项目启动时执行初始化方法
一.applicationContext.xml配置bean <bean id="sensitiveWordInitUtil" class ="com.hx.daz ...
随机推荐
- 从决策树学习谈到贝叶斯分类算法、EM、HMM
从决策树学习谈到贝叶斯分类算法.EM.HMM (Machine Learning & Recommend Search交流新群:172114338) 引言 log ...
- error: ‘for’ loop initial declarations are only allowed in
使用gcc,出现如下错误: thread_join.c:7:5: error: 'for' loop initial declarations are only allowed in C99 mode ...
- oracle常用查询三
查询跟索引有关的数据字典时,可以用下面这条SQL语句: SQL>select * from dictionary where instr(comments,'index')>0; 如果我们 ...
- centos上node.js的安装
CentOS 下安装 Node.js 1.下载源码,你需要在https://nodejs.org/en/download/下载最新的Nodejs版本,本文以v0.10.24为例: cd /usr/lo ...
- apache 开启压缩功能
apache如何开启压缩功能. 1,首先先确认是安装deflatte模块.如果未安装,可以重新编译apache添加参数--enable-deflate=shared ,或者扩展安装deflate模块, ...
- node.js 入门(一)安装
从 https://nodejs.org/ 下载最新版的node.js 下载完成后,双击安装, 一路点击"Next"按钮即可. 等出现上图及表示安装成功. 按"win+r ...
- 【Android】设备标识简介(imei imsi mac地址)
IMEI: 1- 意义: 参考http://zh.wikipedia.org/zh-cn/IMEI 国际移动设备辨识码 ,共15位,和厂商,产地等有关. 2- 获取: 直接查看设备信息,设置-关于手 ...
- 使用SQLiteHelper创建数据库并插入数据
参考<疯狂android讲义>8.4节P424 1.获取SQLiteDatabase实例有2种方法,一是直接new SQLiteDatabase(),另一种使用SQLiteHelper.一 ...
- ORACLE DUAL表详解 .
今天在戴明明同学的QQ空间里看到篇不错的关于DUAL表的文章,自己平时也时而会用到,可是没有系统的学习过,借这个机会学习学习~ ==================================== ...
- Java中加载配置文件的集中方式,以及利用ClassLoader加载文件 .
我们往常进行文件的加载的时候 用到的都是 FileInputStream进行 文件的加载比如下面一个例子 : InputStream in=FileInputStream("1.prope ...