前提
在理解两段式构造函数之前,你首先要知道类的构造器分为
指定构造器
和便利构造器
,并且要理解类的构造代理规则
(可以简单地理解为类的指定构造方法和便利构造方法的相互调用限制)
以下是摘自The Swift Programming Language (3.1)
规则 1 指定构造器必须调用其直接父类的的指定构造器。
规则 2 便利构造器必须调用同类中定义的其它构造器。
规则 3 便利构造器必须最终导致一个指定构造器被调用。
一个更方便记忆的方法是:
• 指定构造器必须总是向上代理
• 便利构造器必须总是横向代理
• 指定构造器只能调用指定构造器(这一条是我加上的)
两段式构造过程
两段式构造过程与其说是一种规则倒不如说是一种思想
先分析下下面这个Demo再往下看:
class Foo {
var a: Int?
var b: Int?
init() {
a = 1
}
}
class Bar: Foo {
var c: Int?
override init() {
// 第一阶段:初始化父类
super.init()
// 第二阶段:子类的Custom化
b = 2
c = 3
}
}
let x = Bar()
x.a // 1
x.b // 2
x.c // 3
当你调用
Bar()
时,(1)首先会调用super.init()
初始化父类,这时候类Foo
的 属性在自身的指定构造器
中被初始化完成;(2)、一旦父类初始化完成,就可以初始化子类的属性,并且可以客户化定制子类的属性,这里个性化设置b=2,c=3
一、类的初始化规则
一个对象的内存只有在其所有存储型属性确定之后才能完全初始化
二、两段式构造过程目的
1、让构造过程更安全;
(说明:两段式构造过程让每个子类与父类都满足了类的初始化规则
)
2、在整个类层级结构中给予了每个类完全的灵活性。
(说明:在Bar的指定构造器中客户化设置了 b=2,c=3,保证了每个类的灵活性)
三、两段式构造过程两个阶段(对应着两段式都早过程的目的)
第一阶段、每个类在使用之前必须调用自身的指定构造器初始化每个存储型属性。
第二阶段、新实例准备使用之前进一步定制它们的存 储型属性。
阶段 1
• 某个指定构造器或便利构造器被调用。
• 完成新实例内存的分配,但此时内存还没有被初始化。
• 指定构造器确保其所在类引入的所有存储型属性都已赋初值。存储型属性所属的内存完成初始化。
• 指定构造器将调用父类的构造器,完成父类属性的初始化。
• 这个调用父类构造器的过程沿着构造器链一直往上执行,直到到达构造器链的最顶部。
• 当到达了构造器链最顶部,且已确保所有实例包含的存储型属性都已经赋值,这个实例的内存被认为已经完 全初始化。此时阶段 1 完成。
阶段 2
• 从顶部构造器链一直往下,每个构造器链中类的指定构造器都有机会进一步定制实例。构造器此时可以访问 self 、修改它的属性并调用实例方法等等。
• 最终,任意构造器链中的便利构造器可以有机会定制实例和使用 self 。
四、安全性检查
Swift 编译器将执行 4 种有效的安全检查,以确保两段式构造过程能不出错地完成:
安全检查1:指定构造器必须先初始化当前类中定义的实例存储属性, 然后才能向上调用父类构造器
安全检查2:指定构造器必须向上调用父类构造器, 然后才能对继承得到的属性赋值
安全检查3:便利构造器必须先调用同一个类的其他构造器, 然后才能对属性赋值
安全检查4:构造器在第一阶段完成之前, 不能调用实例方法, 不能读取实例属性
不懂就药问
网友评论