初始化器initializer
类、结构体、枚举都可以定义初始化器,类似init
方法。
类的初始化
类有2种初始化器:
指定初始化器(designated initializer)
便捷初始化器(convenience initializer)
// 指定初始化器
init(parameters) {
statements
}
// 便捷初始化器, 关键字 convenience
convenience init(parameters) {
statements
}
每个类至少有一个指定初始化器,它是类的默认初始化器、主要初始化器
一个类通常只有一个指定初始化器。偏向于少量 。
- 相互调用规则
指定初始化器必须从它的直系父类调用指定初始化器
便捷初始化器必须从相同的类里调用另一个初始化器
便捷初始化器最终必须调用一个指定初始化器,为了保证安全,保证所有属性都被初始化。
class Person {
var name: String
var age: Int
var height: Int {
get {
return age * 10;
}
}
// 指定初始化器
init(name: String, age: Int) {
self.name = name;
self.age = age;
}
// 以下是 便捷初始化器
convenience init(name: String){
self.init(name: name, age: 0);
}
convenience init (age: Int) {
self.init(name: "", age: age);
}
convenience init(){
self.init(name: "", age: 0);
}
}
var ppp = Person(age: 10);
var ppp1 = Person(name: "Alex");
var PPP2 = Person(name: "alex", age: 10);
Swift在编码安全方面是煞费苦心,为了保证初始化过程的安全,设定了两段式初始化、 安全检查。
-安全检查
-
重写init
当重写父类的指定初始化器时,都必须加上override
如果子类写了一个匹配父类便捷初始化器的初始化器,不用加override
严格来说,子类无法重写父类的便捷初始化器。因为父类的便捷初始化器永远不会通过子类直接调用。
自动继承
如果子类没有自定义任何指定初始化器,它会自动继承父类所有的指定初始化器
如果子类提供了父类所有指定初始化器的实现(要么通过方式1继承,要么重写)
子类自动继承所有的父类便捷初始化器
就算子类添加了更多的便捷初始化器,这些规则仍然适用
子类以便捷初始化器的形式重写父类的指定初始化器,也可以作为满足规则2的一部分
required
用required
修饰指定初始化器,表明其所有子类都必须实现(通过继承或者重写实现)
如果子类重写了required
初始化器,也必须加上required
,不用加override
属性观察器
父类的属性在它自己的初始化器中赋值,不会触发属性观察器。
但在子类的初始化器中赋值,会触发属性观察器。
class Person {
var age: Int {
willSet {
print("willSet", newValue)
}
didSet {
print("didSet", oldValue, age)
}
}
init() {
self.age = 0
}
}
class Student: Person {
override init() {
super.init()
self.age = 1
}
}
// willSet 1
// didSet 0 1
var stu = Student()
可失败初始化器
可以使用init?
定义
class Person {
var name: String
init?(name: String) {
if name.isEmpty {
return nil
}
self.name = name
}
}
不允许同时定义参数标签、参数个数、参数类型相同的可失败初始化器和非可失败初始化器
可以用init!定义隐式解包的可失败初始化器
可失败初始化器可以调用非可失败初始化器,非可失败初始化器调用可失败初始化器需要进行解包
如果初始化器调用一个可失败初始化器导致初始化失败,那么整个初始化过程都失败,并且之后的代码都停止执行
可以用一个非可失败初始化器重写一个可失败初始化器,但反过来是不行的
反初始化器(deinit)
类似于 OC中的dealloc
,当类的实例对象被释放内存时,就会调用实例对象的deinit
。
class Person {
deinit {
print("Person对象销毁了")
}
}
deinit不接受任何参数,不能写小括号,不能自行调用
父类的deinit能被子类继承
子类的deinit实现执行完毕后会调用父类的deinit
网友评论