swift基础—构造过程

存储属性的初始赋值####

构造器######

init() {
// 在此处执行构造过程
}

struct Fahrenheit {
var temperature: Double
init() {
temperature = 32.0
}
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahrenheit")
// 打印 "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 是 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius 是 0.0

参数的内部名称和外部名称######

Color 提供了一个构造器，其中包含三个 Double 类型的构造参数。 Color 也可以提供第二个构造器，它只包含名为 whiteDouble 类型的参数，它被用于给上述三个构造参数赋予同样的值。

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)
// 报编译时错误，需要外部名称

struct Celsius {
var temperatureInCelsius: Double
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
init(_ celsius: Double){
temperatureInCelsius = celsius
}
}
let bodyTemperature = Celsius(37.0)
// bodyTemperature.temperatureInCelsius 为 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?") cheeseQuestion.ask()
// 打印 "Do you like cheese?"
cheeseQuestion.response = "Yes, I do like cheese."

构造过程中常量属性的修改######

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

默认构造器####

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

结构体的逐一成员构造器######

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 的 origin 是 (0.0, 0.0)，size 是 (0.0, 0.0)

let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
// originRect 的 origin 是 (2.0, 2.0)，size 是 (5.0, 5.0)

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// centerRect 的 origin 是 (2.5, 2.5)，size 是 (3.0, 3.0)

类的继承和构造过程####

Swift 为类类型提供了两种构造器来确保实例中所有存储型属性都能获得初始值，它们分别是指定构造器和便利构造器。

指定构造器和便利构造器的语法######

init(parameters) {
statements
}

convenience init(parameters) {
statements
}
类的构造器代理规则######

**规则 2 **

• 指定构造器必须总是向上代理
• 便利构造器必须总是横向代理
两段式构造过程######

Swift 中类的构造过程包含两个阶段。第一个阶段，每个存储型属性被引入它们的类指定一个初始值。当每个存 储型属性的初始值被确定后，第二阶段开始，它给每个类一次机会，在新实例准备使用之前进一步定制它们的存储型属性。

Swift 的两段式构造过程跟 Objective-C 中的构造过程类似。最主要的区别在于第一个阶段，
Objective-C

Swift 编译器将执行 4 种有效的安全检查，以确保两段式构造过程能不出错地完成:

• 某个指定构造器或便利构造器被调用。
• 完成新实例内存的分配，但此时内存还没有被初始化。
• 指定构造器确保其所在类引入的所有存储型属性都已赋初值。存储型属性所属的内存完成初始化。
• 指定构造器将调用父类的构造器，完成父类属性的初始化。
• 这个调用父类构造器的过程沿着构造器链一直往上执行，直到到达构造器链的最顶部。
• 当到达了构造器链最顶部，且已确保所有实例包含的存储型属性都已经赋值，这个实例的内存被认为已经完 全初始化。此时阶段 1 完成。

• 从顶部构造器链一直往下，每个构造器链中类的指定构造器都有机会进一步定制实例。构造器此时可以访问 self 、修改它的属性并调用实例方法等等。
• 最终，任意构造器链中的便利构造器可以有机会定制实例和使用 self
构造器的继承和重写######

Objective-C 中的子类不同，Swift 中的子类默认情况下不会继承父类的构造器。Swift 的这种机制可以防止 一个父类的简单构造器被一个更精细的子类继承，并被错误地用来创建子类的实例。

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

Vehicle 类只为存储型属性提供默认值，而不自定义构造器。因此，它会自动获得一个默认构造器。自动获得的默认构造器总会是类中的指定构造器，它可以用于创建 numberOfWheels0Vehicle 实例:

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 的父类 Vehicle 的默认构造器。这样可以确保 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 的名字是 "Bacon”

Food 类中的构造器 init(name: String) 被定义为一个指定构造器，因为它能确保 Food 实例的所有存储型属性都被初始化。 Food 类没有父类，所以 init(name: String) 构造器不需要调用 super.init() 来完成构造过程。

Food 类同样提供了一个没有参数的便利构造器 init() 。这个 init() 构造器为新食物提供了一个默认的占位名字，通过横向代理到指定构造器 init(name: String) 并给参数 name 传值 [Unnamed] 来实现:

let mysteryMeat = Food()
// mysteryMeat 的名字是 [Unnamed]

class RecipeIngredient: Food {
var quantity: 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 中新引入的属性。随后，构造器向上代理到父类 Foodinit(name: String) 。这个过程满足两段式构造过程 中的安全检查 1。

• RecipeIngredient* 还定义了一个便利构造器 init(name: String) ，它只通过 name 来创建 RecipeIngredient 的实 例。这个便利构造器假设任意 RecipeIngredient 实例的 quantity1 ，所以不需要显式指明数量即可创建出实例。这个便利构造器的定义可以更加方便和快捷地创建实例，并且避免了创建多个 quantity1RecipeIngredient 实例时的代码重复。这个便利构造器只是简单地横向代理到类中的指定构造器，并为 quantity参数传递 1

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

class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name)"
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 species: String
init?(species: String) {
if species.isEmpty { return nil }
self.species = species
}
}

let someCreature = Animal(species: "Giraffe")
// someCreature 的类型是 Animal? 而不是 Animal
if let giraffe = someCreature {
print("An animal was initialized with a species of \(giraffe.species)")
}
// 打印 "An animal was initialized with a species of Giraffe"

let anonymousCreature = Animal(species: "")
// anonymousCreature 的类型是 Animal?, 而不是 Animal
if anonymousCreature == nil {
print("The anonymous creature could not be initialized")
}
// 打印 "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.")
}
// 打印 "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.")
}
// 打印 "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.")
}
// 打印 "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.")
}
// 打印 "This is not a defined temperature unit, so initialization failed."
构造失败的传递

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

CartItem 可失败构造器首先验证接收的 quantity 值是否大于等于 1 。倘若 quantity 值无效，则立即终止 整个构造过程，返回失败结果，且不再执行余下代码。同样地，Product 的可失败构造器首先检查 name 值，假如 name 值为空字符串，则构造器立即执行失败。

if let twoSocks = CartItem(name: "sock", quantity: 2) {
print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
}
// 打印 "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")
}
// 打印 "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")
}
// 打印 "Unable to initialize one unnamed product”
重写一个可失败构造器

class Document {
var name: String?
// 该构造器创建了一个 name 属性的值为 nil 的 document 实例 init() {}
// 该构造器创建了一个 name 属性的值为非空字符串的 document 实例 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:) 。因为子类用另一种方式处理了空字符串的情况，所以不再需要一个可失败构造器，因此子类用一个非可失败构造器 代替了父类的可失败构造器。

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

必要构造器####

class SomeClass {
required init() {
// 构造器的实现代码
}
}

class SomeSubclass: SomeClass {
required init() {
// 构造器的实现代码 }
}

通过闭包或函数设置属性的默认值####

class SomeClass {
let someProperty: SomeType = {
// 在这个闭包中给 someProperty 创建一个默认值
// someValue 必须和 SomeType 类型相同
return someValue
}()
}

boardColor 数组是通过一个闭包来初始化并设置颜色值的:

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

let board = Checkerboard()
print(board.squareIsBlackAtRow(0, column: 1))
// 打印 "true"
print(board.squareIsBlackAtRow(7, column: 7))
// 打印 "false"