init coder aDecoderとは正確には何ですか?


122

私はオンラインコースからiOS開発を学び、カスタムビュー(カスタムテーブルビューセル、コレクションビューセルなど)を作成するたびに、インストラクターは常にこの初期化子を実装します。

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

なぜ正確にいつもこれを呼び出さなければならないのですか?それは何をするためのものか?init内にプロパティを配置できますか?



2
を実装するオブジェクトをサブクラス化する場合、を実装するNSCodingクラスに必要なため、この初期化子を実装する必要がありますNSCoding。少なくともスーパークラスのinitメソッドを呼び出す必要があります。にNSCoderクラスのエンコードされたプロパティが含まれている場合、このメソッドを使用してそれらを回復できます
Paulw11

1
また、Appleの公式Swiftブックのオブジェクト初期化に関するセクションを読むことをお勧めします。
Nicolas Miari

回答:


121

私は反対の方向からこの答えを開始します:ビューの状態をディスクに保存したい場合はどうなりますか?これはシリアル化と呼ばます。逆は逆シリアル化です -ディスクからオブジェクトの状態を復元します。

NSCodingプロトコルは、シリアル化デシリアライズオブジェクトに2つのメソッドを定義しています。

encodeWithCoder(_ aCoder: NSCoder) {
    // Serialize your object here
}

init(coder aDecoder: NSCoder) {
    // Deserialize your object here
}

では、なぜそれがカスタムクラスで必要なのでしょうか。答えはInterface Builderです。オブジェクトをストーリーボードにドラッグして構成すると、インターフェイスビルダーはそのオブジェクトの状態をディスクにシリアル化し、ストーリーボードが画面に表示されたときに逆シリアル化します。それらの方法をInterface Builderに伝える必要があります。少なくとも、サブクラスに新しいプロパティを追加しない場合は、スーパークラスにパックとアンパックを依頼するだけでよいので、super.init(coder: aDecoder)呼び出しにます。サブクラスがより複雑な場合は、サブクラス用に独自のシリアル化および逆シリアル化コードを追加する必要があります。

これは、実行時にオブジェクトを作成するために隠しファイルにコードを書き込むというVisual Studioのアプローチとは対照的です。


すべてをawakeFromNibの中に入れて、使用を忘れないようにしてinit(coder aCoder : NSCoder)ください。
蜂蜜

@ハニー-一言で言えば、「時々それができない」。通常は可能ですが、常にではありません。
Fattie 2017年

@Fattieは、それを行うことの詳細が複雑すぎたり、不必要であったりしないことを知っていますか?説明していただけませんか?
Honey

9
@Honeyは、Interface Builderでオブジェクトを設定したい場合awakeFromNibは機能しません。実行時にawakeFromNib呼び出されます。Interface Builderで行うことはすべて設計時です。あなたがやっていること運ぶために、設計時実行時れるencodeWithCoder(保存)及びinit(coder:)(ロード)
異なるコード

3
@Honeyインターフェイスビルダーを使用してカスタムクラスを構成しない場合(つまり、プログラムでコードを使用して実行する場合)awakeFromNibまたは次のように実行できますinitWIthFrame
コードの違い

28

そのイニシャライザを実装する要件は、次の2つの結果です。

  1. リスコフの置換原則。SがTのサブクラス(たとえばMyViewControllerのサブクラスViewController)である場合、Sオブジェクト(のインスタンスMyViewController)は、Tオブジェクト(のインスタンスViewController)が予期される場所で置換できる必要があります。

  2. 初期化子がサブクラスで明示的に定義されている場合、初期化子はSwiftで継承されません。1つのイニシャライザが明示的に提供されている場合、他のすべてのイニシャライザが明示的に提供される必要があります(これにより、を呼び出すことができますsuper.init(...))。根拠については、この質問を参照してください。それはJavaですが、まだ適用されます。

ポイント1までに、オリジナルViewControllerが実行できるすべてのこと、MyViewControllerサブクラスが実行できるはずです。そのようなことの1つは、指定されたから初期化できるようにすることNSCoderです。ポイント2までに、MyViewControllerサブクラスはこの機能を自動的に継承しません。したがって、この要件を満たす初期化子を手動で指定する必要があります。この場合、スーパークラスに委任するだけで、スーパークラスに通常の動作を実行させることができます。


1
コンストラクターが継承されないことは完全に理にかなっています。基本クラスの(継承された)イニシャライザを使用して派生クラスのインスタンスを初期化すると、派生クラスによって新しく定義(「追加」)された非継承プロパティは決して初期化されます。
Nicolas Miari

3
実際、サブクラスで独自のイニシャライザ実装を提供しない場合、イニシャライザはSwiftで継承されます。新しく定義された非継承プロパティにデフォルト値がある場合、サブクラスに初期化子を記述せずに済み、スーパークラスのすべての初期化子を単純に継承できます。こちらをご覧ください
TheBaj 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.