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() {
            // 构造器的实现代码
        }
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 本章将会介绍 存储属性的初始赋值自定义构造过程默认构造器值类型的构造器代理类的继承和构造过程可失败构造器必要构造器...
    寒桥阅读 769评论 0 0
  • 构造过程是使用类、结构体或枚举类型的实例之前的准备过程。在新实例可用前必须执行这个过程,具体操作包括设置实例中每个...
    莽原奔马668阅读 682评论 0 3
  • 构造过程 构造过程是使用类、结构体或枚举类型的实例之前的准备过程。在新实例可用前必须执行这个过程,具体操作包括设置...
    蛊毒_阅读 724评论 0 2
  • 文/煎饼 相聚的距离不再亲近, 亲近的距离不再遥远, ...
    一直特立独行的饼阅读 263评论 0 0
  • 没有情人的月亮 写不出浪漫 突兀的念想,涂鸦 一纸凄凉 留白太多的日子,等 玫瑰的馨香
    牛舌掌阅读 247评论 0 0