kitoko552.memo

kitoko552のメモ

Swiftのややこしいイニシャライザを整理する

まず、Swiftのイニシャライザに関するキーワードを整理します。

  • 指定イニシャライザ(designated initializer)
  • 簡易イニシャライザ(convenience initializer)
  • 必須イニシャライザ(required initializer)
  • 失敗のあるイニシャライザ(failable initializer)

それぞれの説明を以下に示します。

  • インスタンスの初期化がすべて完了できるイニシャライザ
  • 他のイニシャライザの助けを借りることで初期化を行うイニシャライザ(initの前にconvenienceを付ける)
  • 継承先のサブクラスで必ず実装しなければならないイニシャライザ(initの前にrequiredを付ける)
  • 初期化が失敗した場合にnilを返すイニシャライザ(init?と記述する)

それぞれの例を以下に示します。

class Human {
    var name: String
    
    // 必須イニシャライザ(指定イニシャライザでもある)
    required init(name: String) {
        self.name = name
    }
}

class Man : Human {
    var height: Double
    var weight: Double
    
    // 指定イニシャライザ
    init(name: String, height: Double, weight: Double) {
        // このイニシャライザを呼ぶと初期化がすべて完了する。
        self.height = height
        self.weight = weight
        super.init(name: name)
    }
    
    // 簡易イニシャライザ
    convenience init(height: Double) {
        // 指定イニシャライザを呼ぶことで初期化をする。
        self.init(name: "noname", height: height, weight: 0)
    }

    // 必須イニシャライザを実装(必ず実装しなければならない)
    required init(name: String) {
        self.height = 0
        self.weight = 0
        super.init(name: name)
    }
    
    // 失敗のあるイニシャライザ
    init?(height: Double, weight: Double) {
        // if文の部分を先に書くと、変数を初期化する前にreturnするなと怒られる(なんで?)。
        self.height = height
        self.weight = weight
        super.init(name: "noname")
        
        if height < 0 || weight < 0 {
            return nil // nilを返すことができる。
        }
    }
}

イニシャライザには以下のようなルールがあります。

  1. 指定イニシャライザは、スーパークラスに初期化を任せる前に、自身の変数、定数の初期化を済ませていなければならない。
  2. サブクラスのイニシャライザは、スーパークラスの指定イニシャライザを呼ぶ前に、スーパークラスの変数、定数に値を代入してはいけない。
  3. 簡易イニシャライザは、他のイニシャライザを呼ぶ前に、自身の変数、定数に値を代入してはいけない。
  4. イニシャライザは、ベースクラスでの初期化が終わるまで、インスタンスメソッドを呼び出したり、インスタンス変数を参照したり、selfを値として使ったりしてはいけない。
class Man : Human {
    var height: Double
    var weight: Double
    
    // 指定イニシャライザ
    init(name: String, height: Double, weight: Double) {
        // 1に反する
        super.init(name: name)
        self.height = height
        self.weight = weight
    }
    
    // 簡易イニシャライザ
    convenience init(height: Double) {
        // 3に反する
        self.weight = 0
        self.init(name: "noname", height: height, weight: 0)
    }
    
    // 必須イニシャライザを実装(必ず実装しなければならない)
    required init(name: String) {
        self.height = 0
        self.weight = 0
        self.name = "hoge" // 2に反する
        super.init(name: name)
    }

    // 失敗のあるイニシャライザ
    init?(height: Double, weight: Double) {
        self.height = height
        self.weight = weight
        self.hoge() // 4に反する
        super.init(name: "noname")
        
        if height < 0 || weight < 0 {
            return nil // nilを返すことができる。
        }
    }
    
    func hoge() {
        println("hoge")
    }
}

※この記事では以下の本を参考にしています。

詳解 Swift

詳解 Swift