说明 | |
---|---|
首次发布 | 2018年12月12日 |
最近更新 | 2019年02月03日 |
类的构造代理规则
规则 1: 指定构造器必须调用其直接父类的的指定构造器;
规则 2:便利构造器必须调用同类中定义的其它构造器;
规则 3: 便利构造器必须最终导致一个指定构造器被调用。一个更方便记忆的方法是:
• 指定构造器必须总是向上代理
• 便利构造器必须总是横向代理
以上,引用自《The Swift Programming Language (3.1)》。
类的初始化规则:一个对象的内存只有在其所有存储型属性确定之后才能完全初始化。
两段式构造过程两个阶段
- 第一阶段:每个类在使用之前必须调用自身的指定构造器初始化每个存储型属性。
- 第二阶段:新实例准备使用之前进一步定制它们的存储型属性。
安全检查
- 安全检查1:指定构造器必须先初始化当前类中定义的实例存储属性,然后才能向上调用父类构造器;
- 安全检查2:指定构造器必须向上调用父类构造器,然后才能对继承得到的属性赋值;
- 安全检查3:便利构造器必须先调用同一个类的其他构造器, 然后才能对属性赋值;
- 安全检查4:构造器在第一阶段完成之前,不能调用实例方法,不能读取实例属性。
看下面两个代码示例,代码里给出了相应的注释:
示例一:
// 父类
class BaseHello {
var age: Int
var name: String?
init(age: Int) {
self.age = age
}
}
// 子类
class ChildHello: BaseHello {
var addr: String
// `convenience initializer`,则调用自身的`designated initializer`,如self.init()
convenience init(addr: String) {
self.init(addr: addr, age: 18)
}
init(addr: String, age: Int) {
// super.init(age: age) // 错误:Property 'self.addr' not initialized at super.init call
// 1. 先给当前类的存储变量赋值
self.addr = addr
// 2. 调用super.init(),给继承的属性赋值;
// 如果是`convenience initializer`,则调用自身的`designated initializer`,如self.init()
super.init(age: age)
}
}
示例二:
class ClassA {
var name: String?
init() {
self.name = "no name"
}
}
class ClassB: ClassA {
var age: Int
init(age: Int, name: String) {
// 调用 `super.init()` 之前必须把所有存储属性赋值好
self.age = age
super.init()
// 必须先调用 super.init(),然后才可以对继承过来的属性赋值
self.name = name
}
}
let clsB = ClassB(age: 10, name: "人民重重")
print(clsB.age, clsB.name ?? "")
正确顺序:
- 先给当前类的存储变量赋值
- 调用
super.init()
,如果是 便利构造器,则调用自身的 全能初始化方法,如self.init()
;
- 调用
- 给继承的属性赋值。