【プログラミング初心者】Swift基礎~継承~

#はじめに
今回はオブジェクト指向の考え方の１つである**継承**の使い方について紹介します。
継承がどういうものかは[こちら](https://qiita.com/euJcIKfcqwnzDui/items/3a442bdee2996654dd97#%E7%B6%99%E6%89%BF)で紹介しているので参照してください。

#継承
##定義の仕方
クラスの継承の構文以下となります。

```swift
class 子クラス: 親クラス {

}
```
具体的な実装方法を紹介します。
犬クラス、猫クラスを子クラスとし、親クラスとして動物クラスを継承しているとします。
この場合以下の実装となります。

```swift:Animal.swift
class Animal {

}
```
```swift:Dog.swift
class Dog: Animal {

}
```
```swift:Cat.swift
class Cat: Animal {

}
```
継承していてもインスタンスの生成方法は変わりません。

```swift
let dog = Dog()
let cat = Cat()
```

##メソッドを継承する
次に`Animal`クラスに`eat()`メソッドを定義します。

```Animal.swift
class Animal {
    func eat() {
        print("もぐもぐ")
    }
}
```
すると`Animal`を継承した`Dog`、`Cat`はメソッドを定義しなくても`eat()`を呼び出すことができます。

```swift
let dog = Dog()
let cat = Cat()

dog.eat()
cat.eat()
```
```:実行結果
もぐもぐ
もぐもぐ
```
このように継承することで処理を共通化することができます。

またクラス内で呼び出す場合は自分自身のメソッドとして扱えるので`self.eat()`で呼び出せます。

個別の処理を実装するにはそれぞれのクラスで実装します。
`Dog`に`sitDown()`メソッドを定義します。

```Dog.swift
class Dog: Animal {
    func sitDown() {
        print("おすわり")
    }
}
```
```swift
let dog = Dog()
dog.sitDown()
```
```:実行結果
おすわり
```
これは`Dog`クラスで定義されたメソッドなので当然`Cat`では呼び出せない処理になります。

```swift
let cat = Cat()
cat.sitDown()  // error: Value of type 'Cat' has no member 'sitDown'
```

##プロパティを継承する
プロパティもメソッド同様に継承されます。

```swift:Animal.swift
class Animal {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}
```
```swift:Dog.swift
class Dog: Animal {

}
```
```swift:Cat.swift
class Cat: Animal {
    
}
```
```swift
let dog = Dog(name: "ポチ")
let cat = Cat(name: "ミケ")

print(dog.name)
print(cat.name)
```
```:実行結果
ポチ
ミケ
```
プロパティもメソッド同様それぞれの子クラスで定義したプロパティはそのクラスのオブジェクトしか持ちません。

#オーバーライド
継承したメソッドは子クラスで上書きすることができます。
これを**オーバーライド**と言います。

オーバーライドの構文は以下となります。

```swift
override func 上書きするメソッド() {

}
```
メソッドの頭に`override`を付けるだけです。

`Animal`の`eat()`メソッドをオーバーライドしてみます。

```swift:Animal.swift
class Animal {
    func eat() {
        print("もぐもぐ")
    }
}
```
```Dog.swift
class Dog: Animal {
    override func eat() {
        print("ドッグフードをモグモグ")
    }
}
```
```Cat.swift
class Cat: Animal {

}
```
それぞれの子クラスから`eat()`を呼び出してみましょう。

```swift
let dog = Dog()
let cat = Cat()

dog.eat()
cat.eat()
```
```:実行結果
ドッグフードをモグモグ
もぐもぐ
```
`dog.eat()`ではオーバライドした処理が、`cat.eat()`では`Animal`で定義した処理が実行されていることがわかります。
このようにメソッドを書き換えることができます。

ですがこれではあまり共通化した意味がないように思えます。
よくあるのはオーバーライドし、共通処理＋クラスの独自処理というような実装です。

`Animal`を継承した`Human`クラスを作成します。
`Human`の`eat()`では食べる前に「いただきます」、食べ終わったら「ごちそうさまでした」というようにします。

```swift:Human.swift
class Human: Animal {
    override func eat() {
        print("いただきます")
        super.eat()
        print("ごちそうさまでした")
    }
}
```
```swift
let human = Human()
human.eat()
```
```:実行結果
いただきます
もぐもぐ
ごちそうさまでした
```
`super.eat()`で親クラスである`Animal`の`eat()`メソッドを呼び出しています。
自分自身を使うときは`self`を使います。
一方で`super`は親クラスを表します。

このように共通処理に独自の処理を追加し、クラスを拡張していくことで効率的にコーディングしていきます。

#イニシャライザ
継承した時のイニシャライザ(`init`)の定義の仕方は少し注意が必要です。
こういうものだと覚えてください。

継承していないときのイニシャライザは以下のように定義しますね。

```swift
class SuperClass {
    var property: Int

    init(property: Int) {
        self.property = property
    }
}

let object = SuperClass(property: 0)
```
`SuperClass`クラスを継承した`SubClass`をプロパティなしで定義します。
この場合`SubClass`にイニシャライザが不要なので特に意識することはありません。

```swift
class SubClass: SuperClass {

}
let subObject = SubClass(property: 0)
```
これは勝手に`SuperClass`の`init()`が呼ばれます。

次は`SubClass`に新しくプロパティを追加します。

```swift
class SubClass: SuperClass {
    var subProperty: Int
}
```
すると「Class 'SubClass' has no initializers」とイニシャライザがいないですよと怒られます。
これは継承していなくてもプロパティの初期値が決まっていないので発生するエラーです。
イニシャライザを追加してあげます。

```swift
class SubClass: SuperClass {
    var subProperty: Int

    init(subProperty: Int) {
        self.subProperty = subProperty
    }
}
```
これでいいかと思いきや「'super.init' isn't called on all paths before returning from initializer」とまだ怒られます。
イニシャライザの中で`super.init`が呼ばれていないと言われています。
親クラスのプロパティが初期化されていないため怒られています。
継承した場合、子クラスのイニシャライザの中で親クラスのイニシャライザも呼ばなければいけません。

子クラスのイニシャライズを以下のように修正します。

```swift
class SubClass: SuperClass {
    var subProperty: Int

    init(property: Int, subProperty: Int) {
        self.subProperty = subProperty
        super.init(property: property)
    }
}
let subObject = SubClass(property: 0, subProperty: 0)
```
これでエラーが発生しなくなりました。
ここで注意が必要なのですが、`super.init`は子クラスのプロパティ全ての初期化が終わった後に呼び出してください。
先に親クラスをのイニシャライザを呼び出すとまた怒られます。

・プロパティは何かしらの値で初期化する必要がある
・子クラスのイニシャライザの最後に親クラスのイニシャライザを呼び出す必要がある

現状はこの２点を覚えておけば大丈夫です。

#親クラスのselfでのメソッド呼び出し
以下のようにクラス定義します。

```swift
class SuperClass {
    func testMethod1() {
        print("SuperClass testMethod1 is called")
        self.testMethod2()
    }
    
    func testMethod2() {
        print("SuperClass testMethod2 is called")
    }
}
```
このクラスの`testMethod1()`を呼び出した結果はどうなるでしょう。

```swift
let object = SuperClass()
object.testMethod1()
```
```:実行結果
SuperClass testMethod1 is called
SuperClass testMethod2 is called
```
`testMethod1()`の中で`self.testMethod2()`が呼ばれているのでそれぞれのメソッドが実行されていますね。
これは当然普段通りです。

では以下の場合はどうでしょうか。

```swift
class SuperClass {
    func testMethod1() {
        print("SuperClass testMethod1 is called")
        self.testMethod2()
    }
    
    func testMethod2() {
        print("SuperClass testMethod2 is called")
    }
}

class SubClass: SuperClass {
    override func testMethod1() {
        super.testMethod1()
        print("SubClass testMethod1 is called")
    }
}

let subClass = SubClass()
subClass.testMethod1()
```
子クラスで`testMethod1()`をオーバーライドし親クラスの`testMethod1()`を呼んでいるので以下の結果となります。

```:実行結果
SuperClass testMethod1 is called
SuperClass testMethod2 is called
SubClass testMethod1 is called
```
これもここまで説明してきた内容です。

では以下のように`testMethod2()`をオーバーライドするとどうなるでしょうか。

```swift
class SuperClass {
    func testMethod1() {
        print("SuperClass testMethod1 is called")
        self.testMethod2()
    }
    
    func testMethod2() {
        print("SuperClass testMethod2 is called")
    }
}

class SubClass: SuperClass {
    override func testMethod1() {
        super.testMethod1()
        print("SubClass testMethod1 is called")
    }
    
    override func testMethod2() {
        print("SubClass testMethod2 is called")
    }
}

let subClass = SubClass()
subClass.testMethod1()
```
これを実行すると以下のように出力されます。

```:実行結果
SuperClass testMethod1 is called
SubClass testMethod2 is called
SubClass testMethod1 is called
```
親クラスで呼んでいる`self.testMethod2()`は子クラスの`testMethod2()`を実行していることがわかります。

`self`は自分自身のクラスではなく**インスタンス**を意味します。
つまり`let subClass = SubClass()`で作成した`subClass`を指します。
クラス定義としては`SuperClass`と`SubClass`はそれぞれ別クラスですが、インスタンスは`subClass`ただ１つです。
親クラスで`self`としていてもそれは`subClass`インスタンスを指します。
`testMethod2()`はオーバーライドされているので子クラスの`testMethod2()`の処理を実行するため「SubClass testMethod2 is called」が表示されているというわけです。

以下のパターンも試してみます。

```swift
class SuperClass {
    func testMethod1() {
        print("SuperClass testMethod1 is called")
        self.testMethod2()
    }
    
    func testMethod2() {
        print("SuperClass testMethod2 is called")
    }
}

class SubClass: SuperClass {
    override func testMethod1() {
        super.testMethod1()
        print("SubClass testMethod1 is called")
    }
    
    override func testMethod2() {
        super.testMethod2()
        print("SubClass testMethod2 is called")
    }
}

let subClass = SubClass()
subClass.testMethod1()
```
今度は`SubClass`の`testMethod2()`で`super.testMethod2()`を呼んでいるので親クラスの`testMethod2()`も呼ばれます。

```:実行結果
SuperClass testMethod1 is called
SuperClass testMethod2 is called
SubClass testMethod2 is called
SubClass testMethod1 is called
```

このように意図しない挙動をする可能性ががあるのでメソッドがどのような順序で呼ばれるのかに注意した上で実装してください。
とはいえ最初のうちはそこまで気にすることはないと思うので頭に留めて置く程度でもいいかと思います。

#最後に
今回はSwiftの継承の実装方法について紹介しました。
ですが少し難しい部分があったり、そもそもいつ継承を使うかなどはある程度自分で実装していき経験を積まなければ判断できないかと思います。

iOSアプリ開発では画面オブジェクトは`UIViewController`を継承し実装します。
そのため継承という考え方自体は押さえておく必要はありますが、`UIViewController`を親クラスとして使用するだけです。自分で親クラスを作るわけではありません。
このあたりはある程度パターン化されているので形として覚え、なんとなくこんなことをしてるのかなー程度がわかればいいかと思います。

今回の内容は以上です。
本記事とは別でプログラミング未経験からiOSアプリ開発が行えるようになることを目的とした記事を連載しています。
連載は以下にまとめていますのでそちらも是非もご覧ください。
http://naoyalog.com/