Edited at

Swiftのイニシャライザ

久しぶりに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が初期化されていないとエラーが出ます。初めてこの仕様を見たときは不思議な感じがしました。親を固めて(初期化して)から子を固めるべき、そう感じたからです。

しかし、上のコードの使い方が許されると、次の例ではサブクラスが固まってないのにサブクラスの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


おわりに

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