美文网首页
Swift学习(十四)构造过程

Swift学习(十四)构造过程

作者: 黄成瑞 | 来源:发表于2020-06-18 18:08 被阅读0次
    一、构造过程
    
    1.定义:构造过程是使用类、结构体或枚举类型的实例之前的准备过程。在新实例使用前有个过程是必须的,它包括设置实例中每个存储属性的初始值和执行其他必须的设置或构造过程。你要通过定义构造器来实现构造过程,它就像用来创建特定类型新实例的特殊方法。与 Objective-C 中的构造器不同,Swift 的构造器没有返回值。它们的主要任务是保证某种类型的新实例在第一次使用前完成正确的初始化。
    2.构造过程-构造器(初始化):init()
      析构过程-析构器(释  放):deinit()
    
    二、存储属性的初始赋值
    
    1.类和结构体在创建实例时,必须为所有存储型属性设置合适的初始值。存储型属性的值不能处于一个未知的状态。你可以在构造器中为存储型属性设置初始值,也可以在定义属性时分配默认值。
    2.当你为存储型属性分配默认值或者在构造器中为设置初始值时,它们的值是被直接设置的,不会触发任何属性观察者。
    3.不带形参的构造器init (可以在构造器中为存储型属性设置初始值。同样,你也可以在属性声明时为其设置默认值)
          init() {
              // 在此处执行构造过程
          }
          struct Fahrenheit {
              var temperature: Double
              var temperatureNew = 32.0
              init() {
                  temperature = 32.0
              }
          }
         var f =  Fahrenheit()
         print("The default tenoerature is \(f.temperature)° Fahrenheit") // 打印“The default temperature is 32.0° Fahrenheit”
    
    三、自定义构造过程
    
    1.你可以通过输入形参和可选属性类型来自定义构造过程,也可以在构造过程中分配常量属性。
    2.形参的构造过程:自定义构造过程时,可以在定义中提供构造形参,指定其值的类型和名字。构造形参的功能和语法跟函数和方法的形参相同。
          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。这两个构造器都将单一的实参转换成摄氏温度值,并保存在属性 temperatureInCelsius 中。
    3.形参命名和实参标签:跟函数和方法形参相同,构造形参可以同时使用在构造器里使用的形参命名和一个外部调用构造器时使用的实参标签。然而,构造器并不像函数和方法那样在括号前有一个可辨别的方法名。因此在调用构造器时,主要通过构造器中形参命名和类型来确定应该被调用的构造器。正因如此,如果你在定义构造器时没有提供实参标签,Swift 会为构造器的每个形参自动生成一个实参标签。
          struct Color {
                let red, green, blue: Double 
                init(red: Double, green: Double, blue: Double) { // 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) // 报编译期错误-需要实参标签,如果不通过实参标签传值,这个构造器是没法调用的。如果构造器定义了某个实参标签,就必须使用它,忽略它将导致编译期错误
    4.不带实参标签的构造器形参:如果你不希望构造器的某个形参使用实参标签,可以使用下划线(_)来代替显式的实参标签来重写默认行为。
          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
    5.可选属性类型:如果你自定义的类型有一个逻辑上允许值为空的存储型属性——无论是因为它无法在初始化时赋值,还是因为它在之后某个时机可以赋值为空——都需要将它声明为 可选类型。可选类型的属性将自动初始化为 nil,表示这个属性是特意在构造过程设置为空。
          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?")
          cheeseQuestion.ask() // 打印“Do you like cheese?”
          cheeseQuestion.response = "Yes, I do like cheese."
    6.构造过程中常量属性的赋值:你可以在构造过程中的任意时间点给常量属性赋值,只要在构造过程结束时它设置成确定的值。一旦常量属性被赋值,它将永远不可更改。对于类的实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。例如将上面例子的var text改为let text。
    
    四、默认构造器 
    
    1.默认构造器:如果结构体或类为所有属性提供了默认值,又没有提供任何自定义的构造器,那么 Swift 会给这些结构体或类提供一个默认构造器。这个默认构造器将简单地创建一个所有属性值都设置为它们默认值的实例。由于 ShoppingListItem 类中的所有属性都有默认值,且它是没有父类的基类,它将自动获得一个将为所有属性设置默认值的并创建实例的默认构造器。由于 name 属性是可选 String 类型,它将接收一个默认 nil 的默认值,尽管代码中没有写出这个值。
        class ShoppingListItem {
            var name: String?
            var quantity = 1
            var purchased = false
        }
        var item = ShoppingListItem()
    2.结构体的逐一成员构造器:认构造器,即使存储型属性没有默认值,结构体也能会获得逐一成员构造器。逐一成员构造器是用来初始化结构体新实例里成员属性的快捷方法。新实例的属性初始值可以通过名字传入逐一成员构造器中。memberwise initializer~
          struct Size {
              var width = 0.0, height = 0.0
          }
          let twoByTwo = Size(width: 2.0, height: 2.0)
          let zeroByTwo = Size(height: 2.0)
          print(zeroByTwo.width, zeroByTwo.height)
          例子中定义了一个结构体 Size,它包含两个属性 width 和 height。根据这两个属性默认赋值为 0.0 ,它们的类型被推断出来为 Double。结构体 Size 自动获得了一个逐一成员构造器 init(width:height:)
          当你调用一个逐一成员构造器(memberwise initializer)时,可以省略任何一个有默认值的属性。
    
    五、值类型的构造器代理
    
    1.构造器代理:构造器可以通过调用其它构造器来完成实例的部分构造过程。这一过程称为构造器代理,它能避免多个构造器间的代码重复。
    2.构造器代理的实现规则和形式在值类型和类类型中有所不同。
        值类型:结构体、枚举类型,不支持继承,构造器代理的过程相对简单。对于值类型,你可以使用 self.init 在自定义的构造器中引用相同类型中的其它构造器。并且你只能在构造器内部调用 self.init。请注意,如果你为某个值类型定义了一个自定义的构造器,你将无法访问到默认构造器(如果是结构体,还将无法访问逐一成员构造器)。这种限制避免了在一个更复杂的构造器中做了额外的重要设置,但有人不小心使用自动生成的构造器而导致错误的情况。假如你希望默认构造器、逐一成员构造器以及你自己的自定义构造器都能用来创建实例,可以将自定义的构造器写到扩展(extension)中,而不是写在值类型的原始定义中。
        类类型:类,可以继承自其他类。这意味着类有责任保证其所有继承的存储型属性在构造时也能正确的初始化。
            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(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), 第一个 Rect 构造器 init(),在功能上跟没有自定义构造器时自动获得的默认构造器是一样的。这个构造器是函数体是空的,使用一对大括号 {} 来表示。调用这个构造器将返回一个 Rect 实例,它的 origin 和 size 属性都使用定义时的默认值 Point(x: 0.0, y: 0.0) 和 Size(width: 0.0, height: 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)第二个 Rect 构造器 init(origin:size:),在功能上跟结构体在没有自定义构造器时获得的逐一成员构造器是一样的。这个构造器只是简单地将 origin 和 size 的实参值赋给对应的存储型属性
            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), 第三个 Rect 构造器 init(center:size:) 稍微复杂一点。它先通过 center 和 size 的值计算出 origin 的坐标,然后再调用(或者说代理给)init(origin:size:) 构造器来将新的 origin 和 size 值赋值到对应的属性中,构造器 init(center:size:) 可以直接将 origin 和 size 的新值赋值到对应的属性中。然而,构造器 init(center:size:) 通过使用提供了相关功能的现有构造器将会更加便捷(而且意图更清晰)。
    
    六、类的继承和构造过程
    
    1.类里面的所有存储型属性,包括所有继承自父类的属性,都必须在构造过程中设置初始值。Swift 为类类型提供了两种构造器来确保实例中所有存储型属性都能获得初始值,它们被称为指定构造器和便利构造器。
    2.指定构造器
    指定构造器是类中最主要的构造器。一个指定构造器将初始化类中提供的所有属性,并调用合适的父类构造器让构造过程沿着父类链继续往上进行。类倾向于拥有极少的指定构造器,普遍的是一个类只拥有一个指定构造器。指定构造器像一个个“漏斗”放在构造过程发生的地方,让构造过程沿着父类链继续往上进行。 
    3. 便利构造器
    

    相关文章

      网友评论

          本文标题:Swift学习(十四)构造过程

          本文链接:https://www.haomeiwen.com/subject/ueiyxktx.html