LoginSignup
1
4

More than 3 years have passed since last update.

Swiftのイニシャライザ

Last updated at Posted at 2019-04-11

久しぶりにSwiftのイニシャライザを復習したので、そのときに思ったことや新たに知ったことを、つれづれなるままに書いていきます。つれづれなるままなので「〜思います」系の表現があります。
環境はSwift5.0です。

2つのクラスに継承関係があるとき、サブクラスのinitでは、親のinitを呼ぶ前に自分のところで定義したものを初期化するのはなぜか

class A1 {
    var name: String

    init() {
        print("super")
        name = "unknown"
    }
}

class B1: A1 {
    var age: Int

    override init() {
        print("sub")
        super.init() //エラー Property 'self.age' not initialized at super.init call
        age = 0
    }
}

上の例ではB1のageが初期化されていないとエラーが出ます。初めてこの仕様を見たときは不思議な感じがしました。親を固めて(初期化して)から子を固めるべき、そう感じたからです。
しかし、B1のageが初期化されていない使い方が許されると、次の例ではサブクラスが固まってないのにサブクラスのsomeFunction()が呼び出されてしまうので、こういうのを防ぐ理由もあるかなと気が付きました。

class A1 {
    var name: String

    init() {
        print("super")
        name = "unknown"
        someFunction()
    }

    func someFunction() {
        print("super someFunction")
    }
}

class B1: A1 {
    var age: Int

    override init() {
        print("sub")
        super.init()
        age = 0
    }

    override func someFunction() {
        print("sub someFunction")
        super.someFunction()
    }
}

2つのクラスに継承関係があるとき、親のコンビニエンスinitと同じ引数のinitをサブクラスで指定initとして定義するときの挙動

今回いろいろ調べていてわかったことがあります。誤解を恐れずに書くと
2つのクラスに継承関係があって親が指定initとコンビニエンスinitを持つときに、サブクラスで親と同じ指定initを定義しないで、サブクラスでその指定initが自動生成されると同時に親クラスのコンビニエンスinitも自動生成される条件が整った状況で、親クラスのコンビニエンスinitと同じ引数のinitをサブクラスで指定initとして定義すると、例えばoverrideをつけるように催促するエラーが出ることもなく、コンパイルが通る
です。

class A2 {
    var name: String

    init(name: String) {
        print("super 1")
        self.name = name
    }

    convenience init() {
        print("super 2")
        self.init(name: "unknown")
    }
}

class B2: A2 {

    init() {
        print("sub")
        super.init(name: "unknown")
    }
}

var b2 = B2()
//出力
//sub
//super 1

2つのクラスに継承関係があって親の指定initが2つあるとき、サブクラスでその片方をコンビニエンスinitとして定義するときの挙動

わかったことの2つめは
2つのクラスに継承関係があって親クラスが指定initを2つ持つときに、その片方と同じ引数のinitをサブクラスでコンビニエンスinitとして定義すると、もう片方の指定initは自動生成されて、サブクラスで定義したコンビニエンスinitはoverrideをつけるように催促され、overrideをつけるとそのコンビニエンスinitからself.init()で自動生成された指定initが呼び出せる
です。

class A2 {
    var name: String

    init(name: String) {
        print("super 1")
        self.name = name
    }

    init() {
        print("super 2")
        self.name = "unknown"
    }
}

class B2: A2 {

    convenience override init() {
        print("sub")
        self.init(name: "unknown")
    }
}

var b2 = B2()
//出力
//sub
//super 1

おわりに

*** で詳しく書いてあります。などの情報があれば、よろしくおねがいします。

1
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4