Swift初始化方法遇到的坑
2017-06-25 本文已影响47人
LevineLi
首先感谢这篇文章的作者:callmewhy
阶段构造
Swift 的构造过程分为两个阶段:
第一个阶段 : 每个存储型属性通过引入自己的构造器来设置初始值。
第二个阶段 : 在新实例准备使用之前进一步定制存储型属性。
安全检查
在构造的过程中, Swift 会进行四种安全检查。
安全检查一
指定构造器必须保证它所在类引入的所有属性都必须先初始化完成,之后才能将其它构造任务向上代理给父类中的构造器。
比如下面这段代码就是错误的:
class Food {
var name: String
init(name: String) {
self.name = name
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
super.init(name: name) // ERROR!
self.quantity = quantity
}
}
修改后代码
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
}
安全检查二
指定构造器必须先向上代理调用父类构造器,然后再为继承的属性设置新值。如果没这么做,指定构造器赋予的新值将被父类中的构造器所覆盖。
比如下面这段代码就是错误的:
class Food {
var name: String
init(name: String) {
self.name = name
}
}
class RecipeIngredient: Food {
override init(name: String) {
self.name = "WHY" // ERROR!
super.init(name: name)
}
}
修改后代码
class RecipeIngredient: Food {
override init(name: String)
super.init(name: name)
self.name = "WHY"
}
}
安全检查三
便利构造器必须先代理调用同一类中的其它构造器,然后再为任意属性赋新值。如果没这么做,便利构造器赋予的新值将被同一类中其它指定构造器所覆盖。
比如下面这段代码就是错误的:
class Food {
var name: String
init(name: String) {
self.name = name
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
quantity = 2 // ERROR!
self.init(name: name, quantity: 1)
}
}
修改后代码
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
quantity = 2
}
}
安全检查四
构造器在第一阶段构造完成之前,不能调用任何实例方法、不能读取任何实例属性的值,也不能引用 self 的值。
比如下面这段代码就是错误的:
class Food {
var name: String
init(name: String) {
self.name = name
}
}
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
println(self.name) // ERROR!
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
修改后代码
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
println(self.name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}