跳转至

构造过程

构造过程

目录


**构造过程是为了使用某个类、结构体或枚举类型的实例而进行的准备过程。这个过程包含了**为实例中的每个属性设置初始值**和**为其执行必要的准备和初始化任务。

构造过程是通过定义构造器(Initializers)来实现的,这些构造器可以看做是用来创建特定类型实例的特殊方法。

类实例也可以通过定义析构器(deinitializer)在类实例释放之前执行特定的清除工作。

1.存储属性的初始赋值

类和结构体在实例创建时,必须为所有存储型属性设置合适的初始值。存储型属性的值不能处于一个未知的状态。

你可以在构造器中为存储型属性赋初值,也可以在定义属性时为其设置默认值。

当你为存储型属性设置默认值或者在构造器中为其赋值时,它们的值是被直接设置的,不会触发任何属性观察器。

1.1构造器

构造器在创建某特定类型的新实例时调用。它的最简形式类似于一个不带任何参数的实例方法,以关键字init命名。

下面例子中定义了一个用来保存华氏温度的结构体Fahrenheit,它拥有一个Double类型的存储型属性temperature:

struct Fahrenheit {
    var temperature:Double
    init(){
        temperature = 32.0
    }
}

var f = Fahrenheit()

println("The default temperature is \(f.temperature)")
//打印 The default temperature is 32.0

1.2默认属性值

1
2
3
4
5
6
7
8
struct Fahrenheit {
    var temperature = 32.0
}

var f = Fahrenheit()

println("The default temperature is \(f.temperature)")
//打印 The default temperature is 32.0

2.定制化构造过程

2.1构造参数

你可以在定义构造器时提供构造参数,为其提供定制化构造所需值的类型和名字。构造器参数的功能和语法跟函数和方法参数相同。

下面例子中定义了一个包含摄氏度温度的结构体Celsius。它定义了两个不同的构造器:init(fromFahrenheit:)和init(fromKelvin:),二者分别通过接受不同刻度表示的温度值来创建新的实例:

struct Celsius {
    var temperatureInCelsius: Double = 0.0
    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”

2.2内部和外部参数名

在调用构造器时,主要通过构造器中的参数名和类型来确定需要调用的构造器。正因为参数如此重要,如果你在定义构造器时没有提供参数的外部名字,Swift会为每个构造器的参数自动生成一个跟内部名字相同的外部名。

上面的例子可以修改为:

struct Celsius{
    var temperatureInCelsius:Double = 0.0

    init(fahrenheit:Double){
        temperatureInCelsius = (fahrenheit-32.0)/1.8
    }

    init(kelvin:Double){
        temperatureInCelsius = kelvin - 273.15
    }
}

let boilingPointOfWater = Celsius(fahrenheit: 212)

println(boilingPointOfWater.temperatureInCelsius)
// 100.0

let freezingPointOfWater = Celsius(kelvin: 273.15)

如果不希望为构造器的某个参数提供外部名字,可以使用下划线_来描述它的外部名,覆盖默认行为。

struct Celsius{
    var temperatureInCelsius:Double = 0.0

    init( _ fahrenheit:Double){
        temperatureInCelsius = (fahrenheit-32.0)/1.8
    }

    init(kelvin:Double){
        temperatureInCelsius = kelvin - 273.15
    }
}

let boilingPointOfWater = Celsius(212)

println(boilingPointOfWater.temperatureInCelsius)
// 100.0

let freezingPointOfWater = Celsius(kelvin: 273.15)

2.3可选属性类型

可选类型的属性将自动初始化为nil

class SurveyQuestion{
    var text:String
    var response:String?
    init(text:String){
        self.text = text
    }
    func ask(){
        println(text)
    }
}

let cheeseQuestion = SurveyQuestion(text:"Do you like cheese?")

cheeseQuestion.ask()

cheeseQuestion.response = "Yes , I do like cheese"

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

只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值。

class SurveyQuestion{
    let text:String
    var response:String?
    init(text:String){
        self.text = text
    }
    func ask(){
        println(text)
    }
}

let cheeseQuestion = SurveyQuestion(text:"Do you like cheese?")

cheeseQuestion.ask()

cheeseQuestion.response = "Yes , I do like cheese"

3.默认构造器

Swift为所有属性已提供默认值切自身没有定义任何构造器的结构体或基类,提供一个默认的构造器。

1
2
3
4
5
6
7
class ShoppingListItem{
    var name:String?
    var quantity = 1
    var purchased = false
}

var item = ShoppingListItem()

4.值类型的构造器代理

构造器可以通过调用其它构造器来完成实例部分构造过程。这一过程称为构造器代理,它能减少多个构造器间的代码重复。

如果你为某个值类型定义了一个定制的构造器,你将无法访问到默认构造器,如果是结构体,则无法访问逐一对象构造器。

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()

// 调用第二个构造器

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

//调用第三个构造器

let centerRect = Rect(center: Point(x: 4.0, y: 4.0), size: Size(width: 3.0, height: 3.0))

5.类的继承和构造过程

类里面的所有存储属性,包括所有继承自父类的属性,都必须在构造过程中设置初始值。

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

5.1指定构造器和便利构造器

class Food {
    var name:String
    init(name:String){
        self.name = name
    }

    convenience init(){
        self.init(name:"[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 提供了两个构造器,还继承了Food的init()构造器

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.lowercaseString)"
        output += purchased ? " ✔" : " ✘"
        return output
    }
}

var breakfastList = [
    ShoppingListItem(),
    ShoppingListItem(name: "Bacon"),
    ShoppingListItem(name: "Eggs", quantity: 6),
]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
    println(item.description)
}

5.2构造器链

5.3两段式构造过程

5.4构造器的继承和重载

5.5自动构造器的继承载

6.可失败构造器

如果一个类,结构体或枚举类型的对象,在构造自身的过程中有可能失败,则为其定义一个可失败构造器,是非常有必要的。这里所指的“失败”是指,如给构造器传入无效的参数值,或缺少某种所需的外部资源,又或是不满足某种必要的条件等。

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

// someCreature 累形式Animal? 而不是Animal
let someCreature = Animal(species: "Giraffe")

if let giraffe = someCreature{
    println("An animal was initialied with a species of \(someCreature!.species)")
}

let anonymousCreature = Animal(species: "")

if anonymousCreature == nil{
    println("The anonymous creature could not be initialized")
}

6.1枚举类型的可失败构造器

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 {
    println("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 {
    println("This is not a defined temperature unit, so initialization failed.")
}
// 打印 "This is not a defined temperature unit, so initialization failed."

6.2带原始值的枚举类型的可失败构造器

带原始值的枚举类型会自带一个课失败构造器init?(rawValue)。

enum TemperatureUnit:Character{
    case Kelvin="K",Celsius="C",Fahrenheit="F"
}

let fahrenheitUnit = TemperatureUnit(rawValue: "F")

if fahrenheitUnit != nil {
    println("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 {
    println("This is not a defined temperature unit, so initialization failed.")
}
// prints "This is not a defined temperature unit, so initialization failed."

6.3类的可失败构造器

值类型的可失败构造器,对何时何地触发构造失败这个行为没有任何的限制。类的可失败构造器只能在所有的属性被初始化后,所有类之间的构造器之间的代理调用发生完后触发失败行为。

class Product{
    // 定义为可选类型,来确保失败构造器触发失败条件
    var name:String?
    init?(name:String){
        if name.isEmpty{
            return nil
        }
        self.name=name
    }
}

if let bowTie = Product(name: "bow tie") {
    // 不需要检查 bowTie.name == nil
    println("The product's name is \(bowTie.name)")
}
// 打印 "The product's name is bow tie"

6.4构造失败的传递

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

}

if let twoSocks = CartItem(name: "sock", quantity: 2) {
    println("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
}
// 打印 "Item: sock, quantity: 2"

if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
    println("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")
} else {
    println("Unable to initialize zero shirts")
}
// 打印 "Unable to initialize zero shirts"

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

6.5覆盖一个可失败构造器

7.必要构造器

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

评论