https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-ID203
You implement this initialization process by defining initializers, which are like special methods that can be called to create a new instance of a particular type. Unlike Objective-C initializers, Swift initializers do not return a value. Their primary role is to ensure that new instances of a type are correctly initialized before they are used for the first time.
Swift类、结构体、枚举都支持构造函数, 跟其Java/C++/OC一样在构造函数中设置成员属性的初值。Swift支持多个构造函数,使用不同参数类型区分; 构造函数没有返回值, 初始化过程可以执行失败(并非内存不足,可以是逻辑原因;对比Java只在内存不足时实例化失败)。
前几篇博文已经写了很多类了, 如果没写构造函数,Swift会使用默认的构造函数初始化、成员变量都是对应类型的默认值(跟Java一样)。
Swift的构造函数并非使用类名, 而是使用init关键字。
-
init(parameters) {
-
statements
-
}
struct Color {
let red, green, blue: Double
init(red: Double, green: Double, blue: Double) {
self.red = red //类成员变量和局部变量同名时使用self区分
self.green = green
self.blue = blue
}
init(white: Double) {
red = white
blue = white
green = white
}
}
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)
上面是init构造函数的用法, 可以有多个init函数,在调用时使用类名、括号和参数。
对于可选类型(Optional Type)包括Int? , String?, Double?, 默认值都是nil。
class Question {
var text: String? //默认值nil
var level: Int? //默认值nil
func showText() {
guard text != nil else {
print("text is \(text), values is \(level)")
return
}
print("text is \(text!), value is \(level!)") //注意变量后面跟个叹号,是可选参数类型取值
}
init(_ param: String, _ level: Int) {
print("Question construct2")
text = param
self.level = level
}
init() {
print("Question construct1")
}
}
var question1 = Question() //Question construct1
question1.showText() //text is nil, values is nil
var question2 = Question("what", 1) //Question construct2
question2.showText() //text is what, value is 1
输出:
Question construct1
text is nil, values is nil
Question construct2
text is what, value is 1
类成员常量声明方法:1、直接赋值;2、构造函数里赋值。 使用构造函数必须在所有的构造函数里赋值, 如果只赋一个值建议用直接赋值的方式; 如果可以赋多个值,那么建议用构造函数赋值的方式。
PS: 这个语法跟Java不同, Java在声明常量时必须赋值; 而Swift可以在构造函数里给常量赋值。
class Question {
let constantValue: String
let constantValueExt = "constantExt"
...
convenience init(_ param: String, _ level: Int) {
self.init() //调用其它构造函数, 必须加前缀self
print("Question construct2")
text = param
self.level = level
}
init() {
print("Question construct1")
constantValue = "constant1" //可以修改常量!
}
}
跟Java语言一样, 构造函数可以调用同类、结构体、枚举的其它构造函数, 但必须要添加self前缀。
便利构造函数convenience init, 可以调用同级其它init函数; init函数不能直接调用其它init函数; Xcode会给出提示。
类的初始化过程分为2步, 第一步初始化成员变量, 第二步执行构造函数。(跟Java的执行时序一致)
构造函数可能返回nil,即实例化函数不一定成功, 语法是init? 。
class A {
var value: Int
init() {
value = 0
print("A init value = 0")
}
init(value: Int) {
self.value = value
print("A init with value \(value)")
}
}
class B: A {
var param: Int
var property: String
override init() {
param = 0
property = "zhangsan"
super.init() //调用基类A的init构造函数
print("B init")
}
init(_ value: Int) {
param = 0
property = "lisi"
super.init() //调用基类的构造函数
print("B init with \(value)")
}
init?(_ param: String?) {
guard param != nil else {
return nil
}
self.param = 2
self.property = param!
super.init()
}
}
var b = B(1)
A init value = 0
B init with 1
如上面代码所示, 构造函数可能返回nil时, 使用init?。 Swift还提供了init!语法代替init?,二者作用是一样的,都能返回nil。 注意派生类的init函数必须要调用基类的init函数!否则Xcode会提示错误。
Swift还提供关键字required init作为一种构造函数, 所有派生类必须覆盖该构造函数。
class A {
var value: Int
required init() {
value = 0
print("A init value = 0")
}
...
}
class B: A {
...
required init() { //覆盖基类的构造函数不用写override关键字, 只用required就行了
param = 0
property = "zhangsan"
super.init() //调用基类A的init构造函数
print("B init")
}
...
}
Swift的构造函数有一些特点:
1、使用init作为构造函数, 支持重载;
2、构造函数init?或者init!可以返还nil;
3、调用同级其它init函数时,要声明为convenience init函数;
4、派生类的init函数可以调用基类的nit函数,但必须在给所有成员属性赋值之后;
5、init函数可以继承,但convenience init不能继承;
6、当基类的构造函数声明为required init时,所有派生类必须覆盖该函数;