初始化

Initialization是为准备使用类，结构体或者枚举实例的一个过程。这个过程涉及了在实例里的每一个存储属性设置一个初始值，以及在新实例准备使用之前执行任何其他所必须的设置或初始化。

为存储属性设置初始化值

初始化器

``````init() {
//perform some initialization here
}
``````

``````struct Fahrenheit {
var temperature: Double
init() {
temperature = 32.0
}
}
var f = Fahrenheit()
print("The default temperature \(f.temperature)° Fahrenheit")
//prints "The default temperature is 32.0° Fahrenheit"
``````

默认的属性值

注意:

``````struct Fahrenheit {
var temperature = 32.0
}
``````

自定义初始化

初始化形式参数

``````struct Celsius {
var temperatureInCelsius: Double
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius is 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius is 0.0
``````

局部和外部形式参数名

`Color`提供了一个初始化器，设置为Double类型的参数，命名为`red``green``blue``Color`也提供了第二个初始化器，并带有一个`white`形式参数，用来给三个颜色属性设置为相同的值:

``````struct Color {
let red, green, blue: Double
init(red:Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
init(white: Double) {
red = white
green = white
blue = white
}
}
``````

``````let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)
``````

``````let veryGreen = Color(0.0, 1.0, 0.0)
// this reports a compile-time error - external names are required
``````

初始化器形式参数不用外部名称

``````struct Celsius {
var temperatureInCelsius:Double
init(fromFahrengeit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKevlvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
init(_ celsius: Double) {
temperatureInCelsius = celsius
}
}
let bodyTemperature = Celsius(37.0)
// bodyTemperature.temperatureInCelsius is 37.0
``````

可选的属性类型

``````class SurveyQuestion {
var text: String
var response: String?
init(text: String) {
self.text = text
}
print(text)
}
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
// prints "Do you like cheese?"
cheeseQuestion.response = "Yes, I do like cheese."
``````

在初始化期间分配常量属性

注意:

``````class SurveyQuestion {
let text: String
var response: String?
init() {
self.text = text
}
print(text)
}
}
let beetQuestion = SurveyQuestion(text: "How about beets?")
// prints "How about beets?"
beetsQuestion.response = "I also like beets. (But not with cheese.)"
``````

默认初始化器

Swift为所有的结构体或类提供了一个默认的初始化器。这个默认的初始化器给所有的属性提供了默认值。这个默认的初始化器简单地创建了一个新的实例，这个实例的所有属性都有一个默认值。

``````class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
``````

结构体类型的成员初始化器

`Size`结构体自动接收一个`init(width:heght:)`成员初始化器，你可以使用它来初始化一个新的`Size`实例:

``````struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
``````

值类型的初始化委托(代理)

注意:

``````struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
``````

``````struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
``````

``````let basicRect = Rect()
// basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0)
``````

``````let originRect = Rect(origin: Point(x: 2.0， y: 2.0)，
size: Size(width: 5.0, height: 5.0))
// originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0)
``````

``````let centerRect = Rect(center: Point(x: 4.0, y: 4.0)， size: Size(width:3.0， height: 3.0))
// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)
``````

`init(center:size:)`初始化器已经为它自己的属性分配了`origin``size`的新值。然而，对于`init(center:size:)`初始化器可以更方便(更清楚)来利用现有的已经提供了准确功能的初始化器。

类继承和初始化

Swift为类类型定义了两种初始化器，帮助确保所有的存储属性接收一个初始值。这些被称为指定初始化器和方便初始化器。

指定初始化器和便利初始化器的语法

``````init(parameters) {
statements
}
``````

``````convenience init(parameters) {
statements
}
``````

类类型的初始化器委托/代理

• 指定初始化器必须总是向上委托/代理。
• 便利初始化器必须总是横向委托/代理。

两段式初始化器

Swift的类初始化器包含两个过程。在第一个阶段，通过引入类的初始化器为每一个存储属性分配了一个初始值。一旦每个存储属性的值确定后，第二个阶段就开始了，它给每个类一次机会在新的实例准备使用之前来定制它的存储属性。

注意:

Swift的两段式初始化过程和Objective-C的初始化相似。主要的不同是在第一阶段，Objective-C为每一个属性分配 0 或空值值(例如0或nil)。Swift的初始化过程更加灵活，它允许你设置自定义的初始值，并可以自如应对0或nil作为合法值的情况。

Swift编译器执行四种有效的安全检查来确保两段式初始化过程能够顺利完成:

• 一个指定或便利初始化器被调用。
• 类为这个新的实例分配内存。内存还没有被初始化。
• 此类的指定初始化器确保所有由此类引入的存储属性都有一个值。现在这些存储属性的内存被初始化了。
• 指定的初始化器调用父类的初始化器为其存储属性执行相同的任务。
• 这个调用父类初始化器的过程将沿着初始化器链一直向上进行，直到到达初始化器链的最顶部。
• 当到达了初始化器链最顶部，在链顶部的类确保所有的存储属性都有一个值，此实例的内存被认为完全初始化了，此时第一阶段完成。

• 从顶部初始化器往下，链中的每一个指定初始化器都有机会进一步定制实例。初始化器现在能够访问`self`并且可以修改它的属性，调用它的实例方法，等等。
• 最后，链中任何便利初始化器都有机会定制实例以及使用`slef`

初始化器的继承和重载

注意:

``````class Vehicle {
var numberOfWheels = 0
var description: String {
return "\(numberOfWheels) wheel(s)"
}
}
``````

`Vehicle`类只为它的存储属性提供了一个默认值，并且没有提供自定义的初始化器。因此，它会自动收到一个默认初始化器。请看默认初始化器。默认初始化器(当可用的时候)总是一个类的指定初始化器，也可以被用来创建一个新的`Vehicle`实例，`numberOfWheels`默认为`0`:

``````let vehicle = Vehicle()
print("Vehicle: \(vehicle。description)")
// Vehicle: 0 wheel(s)
``````

``````class Bicycle: Vehicle {
override init() {
super.init()
numberOfWheels = 2
}
}
``````

`Bicycle`类的`init()`初始化器一开始调用`super。init()`，这个方法作用是调用父类的初始化器。这样可以确保`Bicycle`在修改属性之前它所继承的属性`numberOfWheels`能被`Vehicle`类初始化。在调用`super。init()`之后，原始的`numberOfWheels`值会被新值`2`替换。

``````let bicycle = Bicycle()
print("Bicycle: \(bicycle.description)")
// Bicycle: 2 wheel(s)
``````

指定和便利初始化器的操作

``````class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
``````

``````let namedMeat = Food(name: "Bacon")
// namedMeat's name is "Bacon"
``````

`Food``init(name: String)`初始化器作为一个指定初始化器，因为它确保`Food`类实例的所有存储属性被完全初始化。`Food`类没有父类，所以它的`init(name: String)`初始化器不用调用`super。init()`来完成初始化

`Food`类也提供了没有实际参数的便利初始化器`init()``init()`初始化器提供了一个默认的占位名字，通过代理调用同一类中定义的指定初始化器`init(name: String)`并给参数name传值`[Unnamed]`来实现:

``````let mysteryMeat = Food()
// mysteryMeat's name is "[Unnamed]"
``````

``````class RecipeIngredient: Food {
var quartity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
override convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
``````

`RecipeIngredient`类有一个指定初始化器`init(name: String, quantity: Int)`，它可以用来产生新的`RecipeIngredient`实例的所有属性。这个初始化器一开始先将传入的`quantity`实际参数赋值给`quantity`属性，这个属性也仅仅通过`RecipeIngredient`引入新属性。随后，将向上代理给父类`Food``init(name: String)`初始化器。这个过程满足从两段式初始化的安全检查1。

`RecipeIngredient`类也定义一个便利初始化器`init(name: String)`，它只通过name来创建`RecipeIngredient`的实例。这个便利初始化器假设任意`RecipeIngredient`实例的`quantity`值为`1`，所以不用致命数量就可以创建实例。便利初始化器的定义让`RecipeIngredient`更快，更方便地创建实例，并且当创建了多个`quantity``1`的实例时，避免了代码重复。这个便利初始化器只是简单的把代理给了类的指定初始化器，传递了值为`1``quantity`

`RecipeIngredient`类的`init(name: String)`便利初始化器使用了`Food`中指定初始化器`init(name: String)`相同的形式参数。因为便利初始化器从父类重写了一个指定初始化器，它必须使用`override`修饰符(在初始化器的继承和重写中描述)。

``````let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
``````

``````class ShoppingListItem: RecipeIngredient {
var purchased = flase
var desription: String {
var output = "\(quantity) x \(name.lowercaseString)"
output += purchased ? " ✔" : " ✘"
return output
}
}
``````

注意:

`ShoppingListItem`没有定义初始化器来给`purchased`一个初始值，这是因为任何添加到购物单的项的初始状态总是未购买。

``````var breakfastList = [
ShoppingListItem()，
ShoppingListItem(name: "Bacon")，
ShoppingListItem(name: "Eggs", quantity: 6),
]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
print(item.description)
}
// 1 x orange juice ✔
// 1 x bacon ✘
// 6 x eggs ✘
``````

可失败初始化器

注意:

``````struct Animal {
let speices: Stirng
init?(speices: String) {
if species.isEmpty { return nil }
self.species = species
}
}
``````

``````let someCreature = Animal(species: "Giraffe")
// someCreature is of type Animal?, not Animal
if let giraffe = someCreature {
print("An animal was initialized with a species of \(giraffe.species)")
}
// prints "An animal was initialized with a species of Giraffe"
``````

``````let anonymousCreature = Animal(species: "")
// anonymousCreature is of type Animal?, not Animal
if anonymousCreature == nil {
print("The anonymous creature could not be initialized")
}
// prints "The anonymous creature could not be initialized"
``````

枚举类型的可失败初始化器

``````enum TemperatureUnit {
case Kelvin, Celsius, Fahrenheit
init?(symbol: Character) {
switch symbol {
case "K":
self = .Kelvin
case "C":
self = .Celsius
case "F":
self = .Fahrenheit
default:
return nil
}
}
}
``````

``````let fahrenheitUnit = TemperatureUnit(symbol: "F")
if fahrenheitUnit != nil {
print("This is a defined temperature unit, so initialization succeeded.")
}
// prints "This is a defined temperature unit, so initialization succeeded."
let unknownUnit = TemperatureUnit(symbol: "X")
if unknownUnit == nil {
print("This is not a defined temperature unit, so initialization failed.")
}
// prints "This is not a defined temperature unit, so initialization failed."
``````

带有原始值的枚举的可失败初始化器

``````enum TemperatureUnit: Character {
case Kelvin = "K", Celsius = "C", Fahrenheit = "F"
}
let fahrenheitUnit = TemperatureUnit(rawValue: "F")
if fahrenheitUnit != nil {
print("This is a defined temperature unit, so initialization succeeded.")
}
// prints "This is a defined temperature unit, so initialization succeeded."
let unknownUnit = TemperatureUnit(rawValue: "X")
if unknownUnit == nil {
print("This is not a defined temperature unit, so initialization failed.")
}
// prints "This is not a defined temperature unit, so initialization failed."
``````

类的可失败初始化器

``````class Product {
let name: Stirng!
init?(name: String) {
self.name = name
if name.isEmpty { return nil }
}
}
``````

``````f let bowTie = Product(name: "bow tie") {
// no need to check if bowTie.name == nil
print("The product's name is \(bowTie.name)")
}
// prints "The product's name is bow tie"
``````

构造失败的传递

注意:

``````class CartItem: Product {
let quantity: Int!
init?(name: String， quantity: Int) {
self.quantity = quantity
super.init(name: name)
if quantity < 1 { return nil }
}
}
``````

`quantity`属性有一个隐式展开的整型(`Int!`)。和`Product`类的`name`属性相似，这就意味着`quantity`属性在它被分配特定值之前有一个默认初始值`nil`

`CartItem`类的可失败初始化器通过向上代理父类`Product``init(name:)`初始化器。这满足了可失败初始化器在触发构造失败这个行为前必须总是执行构造代理调用这个条件。

``````if let twoSocks = CartItem(name: "sock", quantity: 2) {
print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
}
// prints "Item: sock, quantity: 2"
``````

``````if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
print("Item: \(zeroShirts.name)， quantity: \(zeroShirts.quantity)")
} else {
print("Unable to initialize zero shirts")
}
// prints "Unable to initialize zero shirts"
``````

``````if let oneUnnamed = CartItem(name: "", quantity: 1) {
print("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)")
} else {
print("Unable to initialize one unnamed product")
}
// prints "Unable to initialize one unnamed product"
``````

重写可失败初始化器

注意:

``````class Document {
var name: String?
// this initializer creates a document with a nil name value
init() {}
// this initializer creates a document with a non-empty name value
init?(name: String) {
self.name = name
if name.isEmpty { return nil }
}
}
``````

``````class AutomaticallyNamedDocument: Document {
override init() {
super.init()
self.name = "[Untitled]"
}
override init(name: String) {
super.init()
if name.isEmpty {
self.name = "[Untitled]"
} else {
self.name = name
}
}
}
``````

`AutomaticallyNamedDocument`类用费非失败的`init(name:)`初始化器重写了父类的可失败`init?(name:)`初始化器。因为`AutomaticallyNamedDocument`类用不同的方式处理了空字符串的情况，它的初始化器不会失败，所以它提供了非可失败初始化器来代替。

``````class UntitledDocument: Document {
override init() {
super.init(name: "[Untitled]")!
}
}
``````

必要初始化器

``````class SomeClass {
required init() {
// initializer implementation goes here
}
}
``````

``````class SomeSubclass: SomeClass {
required init() {
// subclass implementation of the required initializer goes here
}
}
``````

通过闭包和函数来设置属性的默认值

``````class SomeClass {
let someProperty: SomeType = {
// create a default value for someProperty inside this closure
// someValue must be of the same type as SomeType
return someValue
}()
}
``````

注意:

`boardColors`数组在一个闭包里被初始化，设置它的颜色值:

``````struc Checkboard {
let boardColors: []Bool] = {
var temporaryBoard = [Bool]()
var isBlack = false
for i in 1...10 {
for j in 1...10 {
temporaryBoard.append(isBlack)
isBlack = !isBlack
}
isBlack = !isBlack
}
return temporaryBoa
}()
func squareIsBlackAtRow(row: Int, column: Int) ->Bool {
return boardColors[(row * 10) + column]
}
}
``````

``````let board = Checkerboard()
print(board.squareIsBlackAtRow(0, column: 1))
// prints "true"
print(board.squareIsBlackAtRow(9, column: 9))
// prints "false"
``````