详细描述请参考: The Swift Programming Language 第二章
构造过程(初始化过程)是使用 类 结构体 或者 枚举类型 一个实例的准备过程
通过定义构造器(Initializers)来实现构造过程,这些构造器可以看做是用来创建特定类型新实例的特殊方法。
与 Objective-C 中的构造器不同,Swift 的构造器无需返回值,它们的主要任务是保证新实例在第一次使用前完成正确的初始化。
类的实例也可以通过定义析构器(deinitializer)在实例释放之前执行特定的清除工作。想了解更多关于析构器的内容,请参考析构过程。
一. 存储属性的初始赋值
类和结构体在创建实例时,必须为所有存储型属性设置合适的初始值。存储型属性的值不能处于一个未知的状态。
设置默认值的两种方式:
1. 在定义属性时候为其设置默认值
2. 在构造器中为存储属性赋值
3. 可选属性类型将自动初始化为nil
如上述代码:
定义了一个Person类, 它用于储存属性
1.储存属性name是可选属性类型, 默认值是nil.
2.储存属性age是Int属性, 在定义时候, 设置默认值是0
3. 储存属性gender, 在制定构造器init()中, 初始化为"Man"
代码: var person = Person() 创建了一个Person类的实例person, 它的name为nil, age = 0, gender = "Man"
注意: 为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观察者(property observers)。
即: 执行代码 var person = Person() 时候, 并不会执行两个didSet{}里面的内容
1. 默认属性值
如前所述, 可以在属性声明时为其设置默认值。如前面的name, age
2. 构造器
同样你可以在构造器中为存储型属性设置初始值。如前面的gender
构造器在创建某特定类型的新实例时调用。它的最简形式类似于一个不带任何参数的实例方法,以关键字init命名。
init() {
// 在此处执行构造过程
}
下面例子中定义了一个用来保存华氏温度的结构体Fahrenheit,它拥有一个Double类型的存储型属性temperature
这个结构体定义了一个不带参数的构造器init,并在里面将存储型属性temperature的值初始化为32.0(华摄氏度下水的冰点)。
注意:
如果一个属性总是使用相同的初始值,那么为其设置一个默认值比每次都在构造器中赋值要好。两种方法的效果是一样的,只不过使用默认值让属性的初始化和声明结合的更紧密。使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型;同时,它也能让你充分利用默认构造器、构造器继承等特性(后续章节将讲到)。
你可以使用更简单的方式在定义结构体Fahrenheit时为属性temperature设置默认值:
struct Fahrenheit {
var temperature = 32.0
}
2.1 自定义构造过程
可以通过输入参数和可选属性类型来自定义构造过程
可以在构造过程中修改常量属性(见后面addition)
2.1.1 构造参数
自定义构造过程时,可以在定义中提供构造参数,指定所需值的类型和名字。构造参数的功能和语法跟函数和方法的参数相同。
下面例子中定义了一个包含摄氏度温度的结构体Celsius。它定义了两个不同的构造器: init(fromFahrenheit:)和init(fromKelvin:), 二者分别通过接受不同刻度表示的温度值来创建新的实例:
第一个构造器拥有一个构造参数,其外部名字为fromFahrenheit, 内部名字为fahrenheit; 第二个构造器也拥有一个构造参数,其外部名字为fromKelvin, 内部名字为kelvin。这两个构造器都将唯一的参数值转换成摄氏温度值,并保存在属性temperatureInCelsius中。
(1) 参数的内部名称和外部名称
跟函数和方法参数相同,构造参数也存在一个在构造器内部使用的参数名字和一个在调用构造器时使用的外部参数名字。
然而, 构造器并不像函数和方法那样在括号前有一个可辨别的名字。所以:
在调用构造器时, 主要通过构造器中的参数名和类型来确定需要调用的构造器。正因为参数如此重要, 所以如果你在定义构造器时没有提供参数的外部名字, Swift 会为每个构造器的参数自动生成一个跟内部名字相同的外部名,就相当于在每个构造参数之前加了一个哈希符号。
以下例子中定义了一个结构体Color,它包含了三个常量:red、green和blue。这些属性可以存储0.0到1.0之间的值,用来指示颜色中红、绿、蓝成分的含量。
Color提供了一个构造器,其中包含三个Double类型的构造参数。Color也可以提供第二个构造器,它只包含Double类型名叫white的参数,它被用于给上述三个构造参数赋予同样的值。
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)
两种构造器都能用于创建一个新的Color实例,你需要为构造器每个外部参数传值。
注意, 如果不通过外部参数名字传值, 你是没法调用这个构造器的。只要构造器定义了某个外部参数名, 你就必须使用它, 忽略它将导致编译错误:
let veryGreen = Color(0.0, 1.0, 0.0) // 报编译时错误,需要外部名称
(2)不带外部名的构造器参数
如果你不希望为构造器的某个参数提供外部名字,你可以使用下划线(_)来显示描述它的外部名, 以此重写上面所说的默认行为。
下面是之前Celsius例子的扩展,跟之前相比添加了一个带有Double类型参数名为celsius的构造器,其外部名用_代替。
调用这种不需要外部参数名称的Celsius(37.0)构造器看起来十分简明的。因此适当使用这种
init(_ celsius: Double)构造器可以提供Double类型的参数值而不需要加上外部名。
3 可选属性类型
如果你定制的类型包含一个逻辑上允许取值为空的存储型属性(不管是因为它无法在初始化时赋值,还是因为它可以在之后某个时间点可以赋值为空) 你都需要将它定义为可选类型optional type。
可选类型的属性将自动初始化为空nil,表示这个属性是故意在初始化时设置为空的。
Addition: 构造过程中常量属性的修改
你可以在构造过程中的任意时间点修改常量属性的值,只要在构造过程结束时是一个确定的值。一旦常量属性被赋值,它将永远不可更改。
注意:
对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改, 不能在子类中修改。
你可以修改上面的SurveyQuestion示例, text用let属性替代var属性, 表示一旦SurveyQuestion的实例被创建之后, text不会再被修改。
尽管text属性现在是常量,我们仍然可以在其类的构造器中设置它的值: