1).类的指定构造方法和便利构造方法
class MyClass {
var a = 0
var b = 0
init(a : Int , b : Int) { //指定构造方法
self.a = a
self.b = b
}
convenience init(a : Int) {
self.init(a: a , b : 0) //调用指定构造方法
}
convenience init(b : Int) { //调用其他便利构造方法
self.init(a:10)
}
}
指定构造(Designated Initializer)方法中,不允许出现构造器代理self.init(...)
便利构造(Convenience Initializer)方法中,一定是通过调用其他的指定构造方法或者便利构造方法来实现初始化的。
(类似于枚举或者结构体中的构造器代理)
2).派生类的构造方法
class SubClass: MyClass { //继承自上面的MyClass
var c = 10
init(c : Int) {
self.c = c //《2》
super.init(a: 10, b: 10) //《1》
}
}
《1》构造方法默认是不会被继承的,基类的存储属性只能通过基类的构造方法来初始化
《2》派生类引入的存储属性要先被初始化,然后再调用父类的构造方法对父类的属性进行初始化
《3》只能通过调用父类的指定构造方法,而不是便利构造方法来对父类的属性进行初始化
3).构造器链
派生类的指定方法构造器,必须调用其直接父类的指定构造器
便利构造器必须调用同类中定义的其他的构造器(指定和便利均可)
便利构造器必须最终以调用一个指定构造器来完成
指定构造器总是向上代理
便利构造器总是横向代理
![image](file:/Users/Yangzhiyong/Desktop/baseImage.png)
4).两段式构造
class SubClass: MyClass { //继承自上面的MyClass
var c = 10
init(c : Int) {
---第一阶段
self.c = c //《2》
super.init(a: 10, b: 10) //《1》
print("第一阶段")
---第二阶段
self.a = 10000
print("第二阶段")
}
}
第一阶段:确保所有的存储属性都初始化完毕
第二阶段:对父类中的存储属性作进一步的处理
两段式构造可以防止属性在被初始化之前访问,也可以防止属性被另外一个构造器意外的赋值
如果A为父类,B继承自A,C继承自B,按照上面的print运行,则结果为:
C: 第一阶段
B:第一阶段
A:第一阶段
A:第二阶段
B:第二阶段
C:第二阶段
构造方法的编译时检查原则:
首先应该将派生类引入的存储属性初始化,然后再向上代理父类的指定构造方法
首先调用父类中的指定构造器实现父类中属性的初始化之后,才可以访问父类中的属性。
在编写便利构造器方法时,我们首先要调用同类中的其他构造方法,然后才可以访问任意属性。
在第一阶段完成之前,我们不能调用任何实例方法,不能访问任何父类中定义的存储属性,也不能引用self。
6).重写指定构造方法(Designated Initalizer)
指定构造方法存在重写,可以在子类中重写为指定构造方法或者便利构造方法均可
便利构造方法不存在重写,在子类中“重写”时,不需要加关键字override
。
这是因为便利构造方法只能横向代理,不可以通过super
关键字来向上代理,所以便利构造方法跟子类没有任何关系。
7).构造器的自动继承
子类自动继承构造方法的条件:
- 如果子类中没有定义任何的构造方法,且子类中所有的存储属性都有默认缺省值,则会自动竭诚父类中所有的构造方法(包括便利构造方法)
- 如果子类中只是重写了父类中的某些(而不是全部)指定构造方法,不管子类中的存储属性是否有缺省值,都不会继承父类中的其他构造方法。
- 如果子类中重写了父类中所有的指定构造方法,不管子类中的存储属性是否有缺省值,都会同时继承父类中所有的便利构造方法
8).必须构造器
必须构造方法是指:该构造方法所属的类的后续子类必须也得实现这个构造方法。关键字required
class MyClass {
required init(a : Int , b : Int) {
print("super")
}
}
class SubClass: MyClass {
required init(a: Int, b: Int) {
print("child")
super.init(a: a, b: b)
}
}