MENU

Swift - 初始化器

May 6, 2016 • Read: 615 • Codes

Swift里,类型实例的初始化使用初始化器来完成,其为一个特殊的函数,没有返回值。

初始化器可以用在类、结构和枚举类型里,类型在初始化的过程中会先分配内存,然后调用初始化器初始化内存。

在我们没有手动写一个初始化器的时候,编译器会自动帮我们创建一个默认的初始化器:

init()

由这个初始化器可以看出,Swift中的初始化器不需要加func关键字。另外,初始化器也只能使用init作为名字,初始化器也只能是实例初始化器,类型初始化器是没有的,如果我们在初始化器前加上static关键字,编译器会报错,告诉我们不能这么做。

每个类至少需要一个初始化器,当然可以有多个,除此之外,初始化器和方法一样,可以指定多种参数:

init(name: String)
初始化实例属性

计算属性是不需要初始化的(当然也并不能),而存储属性则必须被初始化,除非其为可选类型。可选类型可以初始化,也可以不初始化。

存储属性的初始化有几下几种方式:

  • 指定默认值

    class VideoMode {
          //以给定默认值的形式初始化
          var resolution = Resolution()
          //以给定默认值的形式初始化
          var interlaced = false
          //以给定默认值的形式初始化
          var frameRate = 0.0
    }

这种方式比较简单,另外,对于一些比较占用资源的属性,我们可以选择将其延迟加载,要延迟加载某(存储)属性,只要在其前面加上lazy关键字即可:

class VideoMode {
      //延迟加载
      lazy var resolution = Resolution()
      var interlaced = false
      var frameRate = 0.0
}
  • 自定义初始化器

如果我们没有给一个存储属性指定默认值,可以在自定义的初始化器中对其进行初始化:

class VideoMode {
      lazy var resolution = Resolution()
      //没有指定默认值
      var interlaced: Bool
      //没有指定默认值
      var frameRate: Float
      init() {
          //在这里初始化
          interlaced = false
          frameRate = 0.0
      }
}

还有一种方法,有时候我们没办法(或者很麻烦)对一个属性在初始化时给定一个值,这时候我们有两种选择:

我们可以选择使用可选类型,这样,我们就不需要对其初始化了。

class VideoMode {
    //可选类型,没有指定默认值,也没有对其初始化
    var resolution: Resolution?
}

或者,我们可以这样:

class VideoMode {
    //在类型后加上一个`!`号
    var resolution: Resolution!
}

这样,我们可以将其初始化的过程推迟,但我们必须在其被调用前对其赋值,否则会出现运行时错误

实际上,对于给定默认值的方法,编译器会在每个初始化器最前部插入初始化代码。

Convenience Initializer

Designated Initializer为类的主初始化器,负责初始化所有属性。

Convenience Initializer为类的便捷初始化器。其内部必须调用同类的Designated Initializer。Convenience Initializer需要在前面加上convenience关键字。

class VideoMode {
    lazy var resolution = Resolution()
    var interlaced: Bool
    var frameRate: Float
    // Convenience Initializer
    convenience init() {
        // self 不可少
        self.init(interlaced: false, frameRate: 0.0)
    }
    // Designated Initializer
    init(interlaced: Bool, frameRate: Float) {
        self.interlaced = interlaced
        self.frameRate = frameRate
    }
}
类的继承初始化器
class Person {
    var height: UInt64
    var weight: UInt64
    
    init(height: UInt64, weight: UInt64) {
        self.height = height
        self.weight = weight
    }
}

class Student: Person {
    var name: String
    var no  : String
    
    init(height: UInt64, weight: UInt64, name: String, no: String) {
        self.name = name
        //super.init(height: height, weight: weight)  //编译错误
        self.no = no
        //self.weight = self.weight * 2    //编译错误
        super.init(height: height, weight: weight)
        
        self.weight = self.weight * 2
    }
}

子类的初始化器中必须调用父类的Designated Initializer。

如上,Student类继承自Person类,在Student的初始化器中,我们需要先完成本类的属性的初始化,才能调用父类的初始化器,而在父类的初始化器调用之前,父类里的属性是不可操作的。

Tags: Swift
Archives QR Code Tip
QR Code for this page
Tipping QR Code
Leave a Comment