Swift - 初始化

  • 简述

    一旦在 Swift 4 中声明的类、结构和枚举被初始化以准备类的实例。为存储的属性初始化初始值,也为新实例初始化值以进一步进行。创建初始化函数的关键字是通过 'init()' 方法执行的。Swift 4 初始化器与 Objective-C 的不同之处在于它不返回任何值。它的功能是在处理之前检查新创建的实例的初始化。Swift 4 还提供了“取消初始化”过程,用于在实例被释放后执行内存管理操作。
  • 存储属性的初始化角色

    存储属性必须在处理实例之前为其类和结构初始化实例。存储属性使用初始化器来分配和初始化值,从而消除调用属性观察者的需要。初始化器用于存储属性
    • 创建初始值。
    • 在属性定义中分配默认属性值。
    • 要初始化特定数据类型的实例,请使用“init()”。init() 函数内部不传递任何参数。

    句法

    
    init() {
       //New Instance initialization goes here
    }
    

    例子

    
    struct rectangle {
       var length: Double
       var breadth: Double
       init() {
          length = 6
          breadth = 12
       }
    }
    var area = rectangle()
    print("area of rectangle is \(area.length*area.breadth)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    area of rectangle is 72.0
    
    这里的结构 'rectangle' 被初始化为成员长度和宽度为 'Double' 数据类型。Init() 方法用于初始化新创建的成员 length 和 double 的值。矩形的面积是通过调用矩形函数计算和返回的。
  • 默认设置属性值

    Swift 4 语言提供了 Init() 函数来初始化存储的属性值。此外,用户可以在声明类或结构成员时默认初始化属性值。当属性在整个程序中单独使用相同的值时,我们可以单独在声明部分声明它,而不是在 init() 中初始化它。当为类或结构定义继承时,用户可以默认设置属性值。
    
    struct rectangle {
       var length = 6
       var breadth = 12
    }
    var area = rectangle()
    print("area of rectangle is \(area.length*area.breadth)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    area of rectangle is 72
    
    这里不是在 init() 中声明长度和宽度,而是在声明本身中初始化值。
  • 参数初始化

    在 Swift 4 语言中,用户可以使用 init() 将参数初始化为初始化器定义的一部分。
    
    struct Rectangle {
       var length: Double
       var breadth: Double
       var area: Double
       
       init(fromLength length: Double, fromBreadth breadth: Double) {
          self.length = length
          self.breadth = breadth
          area = length * breadth
       }
       init(fromLeng leng: Double, fromBread bread: Double) {
          self.length = leng
          self.breadth = bread
          area = leng * bread
       }
    }
    let ar = Rectangle(fromLength: 6, fromBreadth: 12)
    print("area is: \(ar.area)")
    let are = Rectangle(fromLeng: 36, fromBread: 12)
    print("area is: \(are.area)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    area is: 72.0
    area is: 432.0
    
  • 局部和全局参数

    初始化参数具有类似于函数和方法参数的局部和全局参数名称。局部参数声明用于在初始化体内部访问,外部参数声明用于调用初始化器。Swift 4 初始化器与函数和方法初始化器不同,它们不识别使用哪个初始化器来调用哪些函数。
    为了克服这个问题,Swift 4 为 init() 中的每个参数引入了一个自动外部名称。此自动外部名称与在每个初始化参数之前写入的本地名称等效。
    
    struct Days {
       let sunday, monday, tuesday: Int
       init(sunday: Int, monday: Int, tuesday: Int) {
          self.sunday = sunday
          self.monday = monday
          self.tuesday = tuesday
       }
       init(daysofaweek: Int) {
          sunday = daysofaweek
          monday = daysofaweek
          tuesday = daysofaweek
       }
    }
    let week = Days(sunday: 1, monday: 2, tuesday: 3)
    print("Days of a Week is: \(week.sunday)")
    print("Days of a Week is: \(week.monday)")
    print("Days of a Week is: \(week.tuesday)")
    let weekdays = Days(daysofaweek: 4)
    print("Days of a Week is: \(weekdays.sunday)")
    print("Days of a Week is: \(weekdays.monday)")
    print("Days of a Week is: \(weekdays.tuesday)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    Days of a Week is: 1
    Days of a Week is: 2
    Days of a Week is: 3
    Days of a Week is: 4
    Days of a Week is: 4
    Days of a Week is: 4
    
  • 没有全局名称的参数

    当初始化下划线不需要外部名称时,使用“_”来重写默认行为。
    
    struct Rectangle {
       var length: Double
       
       init(frombreadth breadth: Double) {
          length = breadth * 10
       }
       init(frombre bre: Double) {
          length = bre * 30
       }
       init(_ area: Double) {
          length = area
       }
    }
    let rectarea = Rectangle(180.0)
    print("area is: \(rectarea.length)")
    let rearea = Rectangle(370.0)
    print("area is: \(rearea.length)")
    let recarea = Rectangle(110.0)
    print("area is: \(recarea.length)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    area is: 180.0
    area is: 370.0
    area is: 110.0
    
  • 可选的属性类型

    当某些实例的存储属性不返回任何值时,该属性声明为“可选”类型,指示该特定类型返回“无值”。当存储的属性被声明为“可选”时,它会在初始化期间自动将值初始化为“nil”。
    
    struct Rectangle {
       var length: Double?
       
       init(frombreadth breadth: Double) {
          length = breadth * 10
       }
       init(frombre bre: Double) {
          length = bre * 30
       }
       init(_ area: Double) {
          length = area
       }
    }
    let rectarea = Rectangle(180.0)
    print("area is: \(rectarea.length)")
    let rearea = Rectangle(370.0)
    print("area is: \(rearea.length)")
    let recarea = Rectangle(110.0)
    print("area is: \(recarea.length)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    area is: Optional(180.0)
    area is: Optional(370.0)
    area is: Optional(110.0)
    
  • 在初始化期间修改常量属性

    初始化也允许用户修改常量属性的值。在初始化期间,类属性允许超类而不是子类修改其类实例。例如,在前面的程序中,'length' 在主类中被声明为'variable'。下面的程序变量 'length' 被修改为 'constant' 变量。
    
    struct Rectangle {
       let length: Double?
       
       init(frombreadth breadth: Double) {
          length = breadth * 10
       }
       init(frombre bre: Double) {
          length = bre * 30
       }
       init(_ area: Double) {
          length = area
       }
    }
    let rectarea = Rectangle(180.0)
    print("area is: \(rectarea.length)")
    let rearea = Rectangle(370.0)
    print("area is: \(rearea.length)")
    let recarea = Rectangle(110.0)
    print("area is: \(recarea.length)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    area is: Optional(180.0)
    area is: Optional(370.0)
    area is: Optional(110.0)
    
  • 默认初始化程序

    默认初始值设定项为基类或结构的所有声明属性提供一个新实例,并具有默认值。
    
    class defaultexample {
       var studname: String?
       var stmark = 98
       var pass = true
    }
    var result = defaultexample()
    print("result is: \(result.studname)")
    print("result is: \(result.stmark)")
    print("result is: \(result.pass)")
    
    当我们使用playground运行上面的程序时,我们得到以下结果。-
    
    result is: nil
    result is: 98
    result is: true
    
    上面的程序用类名定义为“defaultexample”。三个成员函数默认初始化为 'studname?' 存储 'nil' 值,'stmark' 为 98,'pass' 为布尔值 'true'。同样,在处理类成员类型之前,可以将类中的成员值初始化为默认值。
  • 结构类型的成员初始化器

    当用户未提供自定义初始化器时,Swift 4 中的结构类型将自动接收“成员初始化器”。它的主要功能是使用默认的 memberwise initialize 来初始化新的结构实例,然后将新的实例属性按名称传递给 memberwise initialize。
    
    struct Rectangle {
       var length = 100.0, breadth = 200.0
    }
    let area = Rectangle(length: 24.0, breadth: 32.0)
    print("Area of rectangle is: \(area.length)")
    print("Area of rectangle is: \(area.breadth)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    Area of rectangle is: 24.0
    Area of rectangle is: 32.0
    
    默认情况下,在将“长度”初始化为“100.0”和“宽度”为“200.0”时,结构会为其成员函数进行初始化。但是在处理变量长度和宽度的过程中,这些值会被重写为 24.0 和 32.0。
  • 值类型的初始化委托

    初始化器委托被定义为从其他初始化器调用初始化器。它的主要功能是作为可重用性来避免跨多个初始化程序的代码重复。
    
    struct Stmark {
       var mark1 = 0.0, mark2 = 0.0
    }
    struct stdb {
       var m1 = 0.0, m2 = 0.0
    }
    struct block {
       var average = stdb()
       var result = Stmark()
       init() {}
       init(average: stdb, result: Stmark) {
          self.average = average
          self.result = result
       }
       init(avg: stdb, result: Stmark) {
          let tot = avg.m1 - (result.mark1 / 2)
          let tot1 = avg.m2 - (result.mark2 / 2)
          self.init(average: stdb(m1: tot, m2: tot1), result: result)
       }
    }
    let set1 = block()
    print("student result is: \(set1.average.m1, set1.average.m2)
    \(set1.result.mark1, set1.result.mark2)")
    let set2 = block(average: stdb(m1: 2.0, m2: 2.0),
    result: Stmark(mark1: 5.0, mark2: 5.0))
    print("student result is: \(set2.average.m1, set2.average.m2)
    \(set2.result.mark1, set2.result.mark2)")
    let set3 = block(avg: stdb(m1: 4.0, m2: 4.0),
    result: Stmark(mark1: 3.0, mark2: 3.0))
    print("student result is: \(set3.average.m1, set3.average.m2)
    \(set3.result.mark1, set3.result.mark2)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    (0.0,0.0) (0.0,0.0)
    (2.0,2.0) 5.0,5.0)
    (2.5,2.5) (3.0,3.0)
    

    初始化器委托规则

    值类型 类类型
    结构和枚举等值类型不支持继承。引用其他初始化程序是通过 self.init 完成的 支持继承。检查所有存储的属性值是否已初始化
  • 类继承和初始化

    类类型有两种初始化器来检查定义的存储属性是否收到初始值,即指定初始化器和便利初始化器。

    指定构造器和便利构造器

    指定初始化器 便利初始化程序
    被视为类的主要初始化 被视为支持类的初始化
    初始化所有类属性并调用适当的超类初始化程序以进行进一步初始化 使用便利初始化器调用指定初始化器来为特定用例或输入值类型创建类实例
    至少为每个类定义一个指定的初始化程序 当类不需要初始化器时,不需要强制定义便利初始化器。
    初始化(参数){ 语句} 方便初始化(参数){ 语句}

    指定初始化程序的程序

    
    class mainClass {
       var no1 : Int // local storage
       init(no1 : Int) {
          self.no1 = no1 // initialization
       }
    }
    class subClass : mainClass {
       var no2 : Int // new subclass storage
       init(no1 : Int, no2 : Int) {
          self.no2 = no2 // initialization
          super.init(no1:no1) // redirect to superclass
       }
    }
    let res = mainClass(no1: 10)
    let print = subClass(no1: 10, no2: 20)
    print("res is: \(res.no1)")
    print("res is: \(print.no1)")
    print("res is: \(print.no2)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    res is: 10
    res is: 10
    res is: 20
    

    便利初始化程序

    
    class mainClass {
       var no1 : Int // local storage
       init(no1 : Int) {
          self.no1 = no1 // initialization
       }
    }
    class subClass : mainClass {
       var no2 : Int
       init(no1 : Int, no2 : Int) {
          self.no2 = no2
          super.init(no1:no1)
       }
       // Requires only one parameter for convenient method
       override convenience init(no1: Int) {
          self.init(no1:no1, no2:0)
       }
    }
    let res = mainClass(no1: 20)
    let print = subClass(no1: 30, no2: 50)
    print("res is: \(res.no1)")
    print("res is: \(print.no1)")
    print("res is: \(print.no2)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    res is: 20
    res is: 30
    res is: 50
    
  • 初始化继承和重写

    默认情况下,Swift 4 不允许其子类为其成员类型继承其超类初始值设定项。继承仅在一定程度上适用于超类初始化器,这将在自动初始化器继承中讨论。
    当用户需要在超类中定义初始化器时,带有初始化器的子类必须由用户定义为自定义实现。当子类必须重写超类时,必须声明“override”关键字。
    
    class sides {
       var corners = 4
       var description: String {
          return "\(corners) sides"
       }
    }
    let rectangle = sides()
    print("Rectangle: \(rectangle.description)")
    class pentagon: sides {
       override init() {
          super.init()
          corners = 5
       }
    }
    let bicycle = pentagon()
    print("Pentagon: \(bicycle.description)")
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    Rectangle: 4 sides
    Pentagon: 5 sides
    

    操作中的指定和便利初始化程序

    
    class Planet {
       var name: String
       init(name: String) {
          self.name = name
       }
       convenience init() {
          self.init(name: "[No Planets]")
       }
    }
    let plName = Planet(name: "Mercury")
    print("Planet name is: \(plName.name)")
    let noplName = Planet()
    print("No Planets like that: \(noplName.name)")
    class planets: Planet {
       var count: Int
       init(name: String, count: Int) {
          self.count = count
          super.init(name: name)
       }
       override convenience init(name: String) {
          self.init(name: name, count: 1)
       }
    }
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    Planet name is: Mercury
    No Planets like that: [No Planets]
    
  • 可失败的初始化程序

    当定义类、结构或枚举值时出现任何初始化程序失败时,必须通知用户。变量的初始化有时会由于以下原因而失败:
    • 无效的参数值。
    • 缺少所需的外部资源。
    • 阻止初始化成功的条件。
    为了捕获初始化方法抛出的异常,Swift 4 生成了一个灵活的初始化,称为“失败初始化器”,以通知用户在初始化结构、类或枚举成员时没有注意到某些事情。捕获可失败初始化程序的关键字是“init?”。此外,不能使用相同的参数类型和名称定义可失败和不可失败的初始值设定项。
    
    struct studrecord {
       let stname: String
       init?(stname: String) {
          if stname.isEmpty {return nil }
          self.stname = stname
       }
    }
    let stmark = studrecord(stname: "Swing")
    if let name = stmark {
       print("Student name is specified")
    }
    let blankname = studrecord(stname: "")
    if blankname == nil {
       print("Student name is left blank")
    }
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    Student name is specified
    Student name is left blank
    
  • 枚举的可失败初始化器

    Swift 4 语言提供了为枚举设置 Failable 初始化器的灵活性,以便在枚举成员没有初始化值时通知用户。
    
    enum functions {
       case a, b, c, d
       init?(funct: String) {
          switch funct {
          case "one":
             self = .a
          case "two":
             self = .b
          case "three":
             self = .c
          case "four":
             self = .d
          default:
             return nil
          }
       }
    }
    let result = functions(funct: "two")
    if result != nil {
       print("With In Block Two")
    }
    let badresult = functions(funct: "five")
    if badresult == nil {
       print("Block Does Not Exist")
    }
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    With In Block Two
    Block Does Not Exist
    
  • 类的可失败初始化器

    使用枚举和结构声明的可失败初始化程序会在其实现中的任何情况下警告初始化失败。但是,类中的可失败初始化程序仅在存储的属性设置为初始值后才会警告失败。
    
    class studrecord {
       let studname: String!
       init?(studname: String) {
          self.studname = studname
          if studname.isEmpty { return nil }
       }
    }
    if let stname = studrecord(studname: "Failable Initializers") {
       print("Module is \(stname.studname)")
    }
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    Module is Optional("Failable Initializers")
    
  • 重写可失败的初始化程序

    与 initialize 一样,用户也可以重写子类中的超类可失败初始化器。超类可失败初始化也可以在子类非失败初始化器中被重写。
    当用不可失败的子类初始化重写可失败的超类初始化器时,子类初始化器不能委托给超类初始化器。
    不可失败的初始化器永远不能委托给可失败的初始化器。
    下面给出的程序描述了可失败和不可失败的初始化程序。
    
    class Planet {
       var name: String
       
       init(name: String) {
          self.name = name
       }
       convenience init() {
          self.init(name: "[No Planets]")
       }
    }
    let plName = Planet(name: "Mercury")
    print("Planet name is: \(plName.name)")
    let noplName = Planet()
    print("No Planets like that: \(noplName.name)")
       
    class planets: Planet {
       var count: Int
       
       init(name: String, count: Int) {
          self.count = count
          super.init(name: name)
       }
       override convenience init(name: String) {
          self.init(name: name, count: 1)
       }
    }
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    Planet name is: Mercury
    No Planets like that: [No Planets]
    
  • init! 可失败的初始化程序

    Swift 4 提供 'init?' 定义一个可选的实例可失败初始化器。定义特定类型 'init!' 的隐式解包可选实例 被指定。
    
    struct studrecord {
    let stname: String
       init!(stname: String) {
          if stname.isEmpty {return nil }
          self.stname = stname
       }
    }
    let stmark = studrecord(stname: "Swing")
    if let name = stmark {
       print("Student name is specified")
    }
    let blankname = studrecord(stname: "")
    if blankname == nil {
       print("Student name is left blank")
    }
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    Student name is specified
    Student name is left blank
    
  • required 初始化程序

    要声明 initialize 'required' 关键字的每个子类,需要在 init() 函数之前定义。
    
    class classA {
       required init() {
          var a = 10
          print(a)
       }
    }
    class classB: classA {
       required init() {
          var b = 30
          print(b)
       }
    }
    let res = classA()
    let print = classB()
    
    当我们使用playground运行上述程序时,我们得到以下结果 -
    
    10
    30
    10