Day12 构造过程

1、存储属性的初始赋值

    init() {
        // 在此处执行构造过程
    }
    //eg:
    
    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
    
    //你可以使用更简单的方式在定义结构体 Fahrenheit 时为属性 temperature 设置默认值:
    struct Fahrenheit1 {
        var temperature = 32.0
    }

2、自定义构造过程

构造参数

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

    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

第一个构造器拥有一个构造参数,其外部名字为 fromFahrenheit ,内部名字为 fahrenheit ;
第二个构造器也拥 有一个构造参数,其外部名字为 fromKelvin ,内部名字为 kelvin

不带外部名的构造器参数

如果你不希望为构造器的某个参数提供外部名字,你可以使用下划线( _ )来显式描述它的外部名,以此重写上面所说的默认行为。

    struct Celsius1 {
        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 = Celsius1(37.0)
    // bodyTemperature.temperatureInCelsius 为 37.0

可选属性类型

下面例子中定义了类 SurveyQuestion ,它包含一个可选字符串属性 response

    class SurveyQuestion {
        var text: String
        var response: String?//可选类型
        init(text: String) {
            self.text = text
        }
        func ask() {
            print(text)
        }
    }
    let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
    //调用函数 ask() 方法
    cheeseQuestion.ask()
    // 打印 "Do you like cheese?"
    cheeseQuestion.response = "Yes, I do like cheese."

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

    class SurveyQuestion1 {
        let text: String  //常量只被初始化一次
        var response: String?
        init(text: String) {
            self.text = text
        }
        func ask() {
            print(text)
        } }
    let beetsQuestion = SurveyQuestion1(text: "How about beets?")
    beetsQuestion.ask()
    // 打印 "How about beets?"
    beetsQuestion.response = "I also like beets. (But not with cheese.)"

3、默认构造器

如果结构体或类的所有属性都有默认值,同时没有自定义的构造器,那么 Swift 会给这些结构体或类提供一个默 认构造器(default initializers)。这个默认构造器将简单地创建一个所有属性值都设置为默认值的实例。

下面例子中创建了一个类 ShoppingListItem ,它封装了购物清单中的某一物品的属性:名字( name )、数量( quantity )和购买状态 purchase state :

    class ShoppingListItem {
        var name: String?
        var quantity = 1
        var purchased = false
    }
    var item = ShoppingListItem()
    print("name is \(item.name)")//name is nil

4、类的继承和构造过程

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

指定构造器和便利构造器

指定构造器是类中最主要的构造器。一个指定构造器将初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化

便利构造器是类中比较次要的、辅助型的构造器。你可以定义便利构造器来调用同一个类中的指定构造器,并为其参数提供默认值。你也可以定义便利构造器来创建一个特殊用途或特定输入值的实例

    //指定构造器和便利构造器的语法
    /*
    init(parameters) {
        statements
    }
    
     convenience init(parameters) {
         statements
     }
     
    */

类的构造器代理规则

[• 指定构造器必须总是向上代理
• 便利构造器必须总是横向代理]

构造器的继承和重写

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

重写父类方法 要添加override 关键字
eg:

    class Vehicle {
        var numberOfWheels = 0
        var description: String {
            return "\(numberOfWheels) wheel(s)"
        }
    }
    
    let vehicle = Vehicle()
    print("Vehicle: \(vehicle.description)")
    // Vehicle: 0 wheel(s)
    
    //下面例子中定义了一个 Vehicle 的子类 Bicycle :
    class Bicycle: Vehicle {
        override init() {
            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”
    
    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)
        }
    }
    
    let oneMysteryItem = RecipeIngredient()
    let oneBacon = RecipeIngredient(name: "Bacon")
    let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
    
    class ShoppingListItem1: RecipeIngredient {
        var purchased = false
        var description: String {
            var output = "\(quantity) x \(name)"
            output += purchased ? " ?" : " ?"
            return output
        }
    }
    
    var breakfastList = [
        ShoppingListItem1(),
        ShoppingListItem1(name: "Bacon"),
        ShoppingListItem1(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 ?

可失败构造器

你可以在一个类,结构体或是枚举类型的定义中,添加一个或 多个可失败构造器。其语法为在 init 关键字后面添加问号( init? )

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

你可以通过该可失败构造器来构建一个 Animal 的实例,并检查构造过程是否成功:

    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"

重写一个可失败构造器

    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
            }
        }
    }

这个子类重写了父类的两个指定构 造器,确保了无论是使用 init() 构造器,还是使用 init(name:) 构造器并为参数传递空字符串,生成的实例中的 name 属性总有初始 "[Untitled]

必要构造器

    //在类的构造器前添加 required 修饰符表明所有该类的子类都必须实现该构造器:
    class SomeClass {
        required init() {
            // 构造器的实现代码
        }
    }
   // 在重写父类中必要的指定构造器时,不需要添加 override 修饰符:
    class SomeSubclass: SomeClass {
        required init() {
            // 构造器的实现代码
        }
    }

你可能感兴趣的:(Day12 构造过程)