required init?(coder aDecoder: NSCoder) { }について考えてみよう!①

この記事は2015年11月24日に書かれたものです。内容が古い可能性がありますのでご注意ください。


UIButtonを継承したオリジナルボタンのクラスを作成する②
の時には少しだけ触れたけど、ほぼスルーした

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

の部分について考えてみたいと思います。というのも、なぜこのイニシャライザを書かなくてはいけないのか、
ってことですね。

細かいことを突き詰めるとイニシャライザの継承のルールなども絡んでくるので、
そういうのは飛ばしてざっくり説明します。

そもそもrequiredイニシャライザってなに?

「required」を直訳すると「必須」という意味になります。
必須、つまり必ず書いてあげなくてはいけないイニシャライザということです。
じゃあ、どんな時に必ず書くの?ってことですが、それは、
そのrequiredイニシャライザが定義されているクラスを継承して新しいクラスを作る時
です。その時に必ず書いてあげる必要があるんです。
難しい言葉で言うと、スーパークラスでrequiredがついたイニシャライザを
強制的にオーバーライド(上書き)するんですね。

で、サブクラス内でも「override」とは書かずに「required」と書く、と。

うーん、複雑。

では、以下の例で見てみましょう。

class SmallNum {
    
    var a:Int = 1
    var b:Int = 2
    
    init(num:Int){
        b = num
    }
    
    init(num1:Int, num2:Int){
        a = num1
        b = num2
    }
}

class BigNum:SmallNum {
    
    var A:Int = 10
    var B:Int = 20
    
    init(NUM:Int){
        B = NUM
        super.init(num: 100)
    }
}

このSmallNumとBigNumの2つのクラスを定義します。ViewController.swiftに追加してもいいですし、新しく
ファイルを作成して追加してもどっちでも構いません。とりあえずどこかに書きます。
この状態ではクラスの定義に全く問題が無いためエラーもありません。
で、次に10行目の
init(num1:Int, num2:Int){
の先頭にrequiredを追加してみます。
するとこんな感じに。

class SmallNum {
    
    var a:Int = 1
    var b:Int = 2
    
    init(num:Int){
        b = num
    }
    
    required init(num1:Int, num2:Int){  //頭にrequiredを付けただけ
        a = num1
        b = num2
    }
}

class BigNum:SmallNum {
    
    var A:Int = 10
    var B:Int = 20
    
    init(NUM:Int){
        B = NUM
        super.init(num: 100)
    }
}

ただrequiredを付けただけですね。
す、すると!なんと!

エラーが出てるではありませんか。笑

しかもそのエラーを見てみると、UIButtonを継承したオリジナルボタンのクラスを作成する②の時の
エラーとほとんど同じ!
s11_1
なのでとりあえずダブルクリックしてコードを補ってもらう。これも同じですね。
出来上がったコードが以下のとおりです。

class SmallNum {
    
    var a:Int = 1
    var b:Int = 2
    
    init(num:Int){
        b = num
    }
    
    required init(num1:Int, num2:Int){
        a = num1
        b = num2
    }
}

class BigNum:SmallNum {
    
    var A:Int = 10
    var B:Int = 20
    
    init(NUM:Int){
        B = NUM
        super.init(num: 100)
    }

    required init(num1: Int, num2: Int) {
        fatalError("init(num1:num2:) has not been implemented")
    }
}

s11_2
以上のことをまとめると、

①通常のイニシャライザ(requiredが付かないイニシャライザ)はサブクラスで実装しても実装しなくても良い。

上の例でいうと4~6行目のinit(num:Int){ }はサブクラスのBigNumでは実装されていませんよね。
実装しても実装しなくてもいいんです。ただし、再定義する場合はoverrideを必ず付ける必要があります。
(overrideとかの使い方はイニシャライザを詳しく説明する時に回したいと思います。)

②必須イニシャライザ(requiredが付いてるイニシャライザ)はサブクラスで絶対実装し直さないといけない。

26~28行目の部分です。スーパークラスでrequiredでイニシャライザが実装されているので、サブクラスでも実装する必要
があります。サブクラスで実装する際もoverrideではなくて、requiredを付けます。

ってことですね。

今回はここまで。次回はUIButtonクラスを継承して新しいクラスを作成した際に実装した

required init?(coder aDecoder: NSCoder) {
}

がそもそもどこで定義されているかを探していきたいと思います。

  • このエントリーをはてなブックマークに追加

PAGE TOP