构造过程是使用类、结构体或枚举类型的实例之前的准备过程。包括设置实例中每个存储属性的初始值和执行其他必须的设置或构造过程。
一、构造器
构造器在创建某个特定类型的新实例时被调用。它的最简形式类似于一个不带任何形参的实例方法,以关键字 init 命名:
init() {
// 在此处执行构造过程
}
二、存储属性的初始赋值
类和结构体在创建实例时,必须为所有存储型属性设置合适的初始值,存储型属性的值不能处于一个未知的状态。
1、可以在构造器中为存储型属性设置初始值;
2、也可以在定义属性时分配默认值。
如下定义了一个用来保存华氏温度的结构体 Fahrenheit,它拥有一个 Double 类型的存储型属性 temperature,如果不给temperature设置一个初始值的话,就会报错。
正确写法:
//在**构造器中**为存储型属性设置初始值
struct Fahrenheit {
var temperature: Double
init() {
temperature = 20.0
}
}
//通过在**属性声明**时为 temperature 提供默认值
struct Fahrenheit {
var temperature = 32.0
}
三、自定义构造过程
1、自定义构造过程时,可以在定义中提供构造形参,指定其值的类型和名字
struct Person {
var name: String = "King"
init(fromFamilyName familyName:String) {
name = name + " " + familyName
}
}
let person = Person(fromFamilyName: "David")
print(person.name)
//King David
上面的构造器有一个构造形参,其实参标签为 fromFamilyName,形参命名为 familyName;
2、形参命名和实参标签
struct Color {
let red: Double, green: Double, blue: Double
init(red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
}
let color = Color(red: 1.0, green: 2.0, blue: 2.0)
Color 提供了一个构造器,为红蓝绿提供三个 Double 类型的形参命名red,green,blue,在创建实例的时候他们就是构造器的实例标签。使用时,创建Color实例的时候,必须用构造器的实参标签*,如果不通过实参标签传值,这个构造器是没法调用的。如果构造器定义了某个实参标签,就必须使用它。
let veryGreen = Color(0.0, 1.0, 0.0)
// 报编译期错误-需要实参标签
3、不带实参标签的构造器形参
如果你不希望在构造器中某个形参使用实参标签,可以使用下划线(_)来代替显式的实参标签来重写默认行为。
struct Color {
let red: Double
init(_ red: Double) {
self.red = red
}
}
let color = Color(red: 1.0)
// 错误调用: 报错 Extraneous argument label 'red:' in call
let color = Color(1.0)
// 正确调用(用下划线的时候,实参标签red是不可以用的)
4、可选属性类型
如果你自定义的类型有一个逻辑上允许值为空的存储型属性——无论是因为它无法在初始化时赋值,还是因为它在之后某个时机可以赋值为空——都需要将它声明为 可选类型。可选类型的属性将自动初始化为 nil,表示这个属性是特意在构造过程设置为空。
struct Question {
var reason :String
var response: String?
init(reason: String) {
self.reason = reason
}
}
//上面构造器里面只需要(并且必须要)初始化reason的值,不需要设置response的值,因为response的值是可选的,已经自动出海刷为nil了。
5、构造过程中常量属性的赋值
你可以在构造过程中的任意时间点给常量属性赋值,只要在构造过程结束时它设置成确定的值。一旦常量属性被赋值,它将永远不可更改。
class Question {
let reason :String
var response: String?
init(reason: String) {
self.reason = reason
}
}
let question = Question(reason: "i love it") //只能在构造过程给常量属性reason赋值
question.reason = "么么哒" //常量属性reason的值不能被修改(报错:Cannot assign to property: 'reason' is a 'let' constant)
print(question.reason)
// 打印i love it
6.默认构造器
如果结构体或类为所有属性提供了默认值,又没有提供任何自定义的构造器,那么 Swift 会给这些结构体或类提供一个默认构造器。
class Question {
let reason :String = "i love it"
var response: String?
}
let question = Question()
由于 Question 类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个将为所有属性设置默认值的并创建实例的默认构造器(由于 response 属性是可选 String 类型,它将接收一个默认 nil 的默认值,尽管代码中没有写出这个值)
6、结构体的逐一成员构造器
结构体如果没有定义任何自定义构造器,它们将自动获得一个逐一成员构造器。不像默认构造器,即使存储型属性没有默认值,结构体也能会获得逐一成员构造器。
struct Size {
var width : Double
var height: Double
}
let size = Size(width: 1.0, height: 2.0)
像上面的结构体size,可以省略构造器。如果属性都赋予初始值得话,在创建结构体实例的时候还可以如下:创建实例的时候省略属性,这时候自动分配的构造器会使用默认值
struct Size {
var width = 1.0
var height = 2.0
}
let size = Size()
7、值类型的构造器代理
构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能避免多个构造器间的代码重复。
struct Point {
var x = 0.0
var y = 0.0
}
struct Size {
var width = 0.0
var height = 0.0
}
struct Rect {
var orgin = Point()
var size = Size()
init() {
}
init(orgin:Point, size:Size) {
self.orgin = orgin
self.size = size
}
init(center:Point, size:Size) {
let orginX = center.x - size.width/2
let orginY = center.y - size.height/2
self.init(orgin: Point(x: orginX, y: orginY), size:size)
}
}
let baseReact = Rect()
let orginReact = Rect(orgin: Point(x: 1.0, y: 2.0), size: Size(width: 1.0, height: 2.0))
let centerReact = Rect(center: Point(x: 1.0, y: 2.0), size: Size(width: 1.0, height: 2.0))