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

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


それでは前回の続きです。
UIButtonクラスを継承した新しいクラス(MyButtonクラスとしています)を作成した際に
自動で挿入されるrequired init?(coder aDecoder: NSCoder) { }というイニシャライザに
ついてです。

前回requiredイニシャライザというものについて説明しましたね。
一言で表すなら、
「スーパークラスでrequiredイニシャライザが実装されているよ。
だからサブクラスでも実装しないといけないんだよ」

というものでした。
それを踏まえた上で見ていきましょう。

required init?(coder aDecoder: NSCoder) { }を探してみよう!

MyButtonクラスでこのrequiredイニシャライザを実装しなくてはならないということは、
そのスーパークラスであるUIButtonクラスでこのrequiredイニシャライザが定義されている
んじゃないか!と推測を立てて、UIButtonクラスの中身を見てみましょう。

キーボードの「command」キーを押しながら該当クラスにカーソルを合わせてクリックすると、
そのクラスの定義を見ることができます。カーソルも指の形になりますので、わかりやすいと
思います。
s12_1
なお、今回はクラスの定義を見ますがメソッドやプロパティをクリックすればその定義を確認することも
できますので、いろいろ試してみると良いでしょう。
(エラーの赤い!マークが出ていますが、今回のrequiredイニシャライザの部分とは関係ありません
ので無視します。)

表示されたUIButtonの定義が次のものになります。
s12_2

英語ばかりで目がチカチカする。。

ただ、今知りたいのはイニシャライザの部分だけですので、プロパティやメソッドはすべて無視して赤枠の
部分だけに注目します。

が、しかし!!

required init?(coder aDecoder: NSCoder) { }なんてどこにも書かれてないではありませんか…。

うーん、困った困った。

まぁ書かれてないものは仕方がないので、他の部分を探してみます。
青枠の部分を見てみると、UIButtonクラスはUIControlクラスを継承しているので、今度はそっちを
「command」キー+クリックで定義を確認してみましょう。
s12_3

あれ、UIControlクラスにはそもそもイニシャライザが定義されてない!

うーん、、ここもハズレっぽいので、UIControlクラスのスーパークラスであるUIViewクラスを
同じように見てみましょう。
s12_4

あった!!

UIViewクラスで定義されていたんですね。
もうちょっと正確に言うと、NSCodingプロトコル(青枠)で定義されているものをUIViewクラスで実装している。
ということになります。

まぁなにはともあれ、見つかって良かった。

でも、あれ!?!?

この部分をよく見てみると、

    public init?(coder aDecoder: NSCoder)

requiredって書かれてない!?なぜ??

ってことで、このイニシャライザを公式リファレンスで詳しく見てみることにしましょう。
このinit?と書かれているところをクリックしてカーソルを合わせて、右側のユーティリティエリアの
Quik Help(?マークのアイコン)をクリックします。
そして表示された下の方に「Reference」と書かれている部分があるので、そこから公式リファレンスの
ページに飛ぶことができます。
s12_5
すると、別画面で以下のようにNSCodingのページを表示することができます。
s12_6

あ、requiredって書いてる。。笑

ってことですので、init?(coder aDecoder: NSCoder){ }はrequiredイニシャライザだということが
わかりました。

わざわざ公式リファレンスを見なくてはならないなんてなんだか腑に落ちないですけども、とりあえず
見つかって良かったです。
それとも、このどこかで確認することができるのかな??そこまでは見つけられなかった…。
(知っている人いたら教えてくださいm(__)m)

つまりまとめるとどういうこと?

init?(coder aDecoder: NSCoder){ }のイニシャライザはNSCodingプロトコルで定義されているもので、
それがUIViewクラスで実装されていることがわかりました。
ちょっとまとめてみると、以下のようになります。

UIViewクラス

・init(frame: CGRect){} 指定イニシャライザ
・init?(coder aDecoder: NSCoder) 必須イニシャライザ

が定義されている。

UIControlクラス

・init(frame: CGRect){} 指定イニシャライザ
・init?(coder aDecoder: NSCoder){} 必須イニシャライザ

UIViewクラスを継承しているので、UIViewクラスの両方の
イニシャライザをそのまま使える。

UIButtonクラス

・init(frame: CGRect){} 指定イニシャライザ
・init?(coder aDecoder: NSCoder){} 必須イニシャライザ
・convenience init(type buttonType: UIButtonType){} コンビニエンスイニシャライザ

UIControlクラスを継承しているので、UIControlクラスの両方の
イニシャライザ(元をたどればUIViewクラスのイニシャライザ)
をそのまま使える。

MyButtonクラス(自作クラス)

・init(){} 自作の指定イニシャライザ
・init?(coder aDecoder: NSCoder){} 必須イニシャライザ

UIButtonクラスを継承した自作クラスだが、継承のルールに則っていないため
UIButtonクラスのイニシャライザを継承していない。しかし、init?(coder aDecoder: NSCoder)は
必須イニシャライザのため明示的に記述をする必要がある。

イニシャライザの継承のルールが色々と複雑なため、継承されたり継承されなかったりすることがあるのですが、
UIButtonやその親であるUIControlは継承のルール上ちゃんと継承されているため、わざわざ書く必要がない(定義の中にも
書かれてない)のですが、今回の自作のMyButtonクラスは継承されていないため明示的に必須イニシャライザを再実装
してあげないといけないのですね。

まぁなんとも複雑ですけども、そういう風になっています。

継承のルール等はSwiftの公式リファレンスを読むのが一番いいかもしれません。英語ですが…。
いずれ機会があればここで説明できればいいな、と思っています。

終わり。

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

PAGE TOP