Swift里,类型实例的初始化使用初始化器来完成,其为一个特殊的函数,没有返回值。
初始化器可以用在类、结构和枚举类型里,类型在初始化的过程中会先分配内存,然后调用初始化器初始化内存。
在我们没有手动写一个初始化器的时候,编译器会自动帮我们创建一个默认的初始化器:
init()由这个初始化器可以看出,Swift中的初始化器不需要加func关键字。另外,初始化器也只能使用init作为名字,初始化器也只能是实例初始化器,类型初始化器是没有的,如果我们在初始化器前加上static关键字,编译器会报错,告诉我们不能这么做。
每个类至少需要一个初始化器,当然可以有多个,除此之外,初始化器和方法一样,可以指定多种参数:
init(name: String)初始化实例属性
计算属性是不需要初始化的(当然也并不能),而存储属性则必须被初始化,除非其为可选类型。可选类型可以初始化,也可以不初始化。
存储属性的初始化有几下几种方式:
指定默认值
class VideoMode { //以给定默认值的形式初始化 var resolution = Resolution() //以给定默认值的形式初始化 var interlaced = false //以给定默认值的形式初始化 var frameRate = 0.0 }这种方式比较简单,另外,对于一些比较占用资源的属性,我们可以选择将其延迟加载,要延迟加载某(存储)属性,只要在其前面加上
lazy关键字即可:class VideoMode { //延迟加载 lazy var resolution = Resolution() var interlaced = false var frameRate = 0.0 }自定义初始化器
如果我们没有给一个存储属性指定默认值,可以在自定义的初始化器中对其进行初始化:
class VideoMode { lazy var resolution = Resolution() //没有指定默认值 var interlaced: Bool //没有指定默认值 var frameRate: Float init() { //在这里初始化 interlaced = false frameRate = 0.0 } }
还有一种方法,有时候我们没办法(或者很麻烦)对一个属性在初始化时给定一个值,这时候我们有两种选择:
我们可以选择使用可选类型,这样,我们就不需要对其初始化了。
class VideoMode {
//可选类型,没有指定默认值,也没有对其初始化
var resolution: Resolution?
}或者,我们可以这样:
class VideoMode {
//在类型后加上一个`!`号
var resolution: Resolution!
}这样,我们可以将其初始化的过程推迟,但我们必须在其被调用前对其赋值,否则会出现运行时错误。
实际上,对于给定默认值的方法,编译器会在每个初始化器最前部插入初始化代码。
Convenience Initializer
Designated Initializer为类的主初始化器,负责初始化所有属性。
Convenience Initializer为类的便捷初始化器。其内部必须调用同类的Designated Initializer。Convenience Initializer需要在前面加上convenience关键字。
class VideoMode {
lazy var resolution = Resolution()
var interlaced: Bool
var frameRate: Float
// Convenience Initializer
convenience init() {
// self 不可少
self.init(interlaced: false, frameRate: 0.0)
}
// Designated Initializer
init(interlaced: Bool, frameRate: Float) {
self.interlaced = interlaced
self.frameRate = frameRate
}
}类的继承初始化器
class Person {
var height: UInt64
var weight: UInt64
init(height: UInt64, weight: UInt64) {
self.height = height
self.weight = weight
}
}
class Student: Person {
var name: String
var no : String
init(height: UInt64, weight: UInt64, name: String, no: String) {
self.name = name
//super.init(height: height, weight: weight) //编译错误
self.no = no
//self.weight = self.weight * 2 //编译错误
super.init(height: height, weight: weight)
self.weight = self.weight * 2
}
}子类的初始化器中必须调用父类的Designated Initializer。
如上,Student类继承自Person类,在Student的初始化器中,我们需要先完成本类的属性的初始化,才能调用父类的初始化器,而在父类的初始化器调用之前,父类里的属性是不可操作的。