web-dev-qa-db-ja.com

Swiftサブクラスは*常に* super.init()を呼び出す必要がありますか?

Swiftサブクラスがある場合:

  1. selfにアクセスする必要はありません
  2. selfのプロパティにアクセスする必要はありません

サブクラスのsuper.init()メソッドでinit()を呼び出す必要がありますか?

*注:これは、上記の1と2に記載されている詳細のために、尋ねられて回答されたものとは異なる質問です ここではSO

30
bearMountain

いいえ、必要はありません。

次のクラスがあるとします。

_class a {
    let name: String

    init() {
        name = "james"
    }
}

class b: a {
    let title: String

    override init() {
        title = "supervisor"
    }
}
_

で変数をインスタンス化する場合

let myVar = b()

そして、

  • boverride init()が呼び出されます
  • 次に、ainit()が呼び出されます

明示的にsuper.init()を呼び出さなかったとしても。


これは、SwiftユーザーのメーリングリストでChris Laettnerによって確認されています。これは、スーパークラスに引数なしのinitを持つ指定されたイニシャライザが1つある場合に始まります。これが、NSObjectから派生するときにsuper.init()を呼び出す必要がない理由です。

*以下のWingzeroのコメントに感謝

25
bearMountain

ドキュメントから:

指定イニシャライザは、直接のスーパークラスから指定イニシャライザを呼び出す必要があります。

また、自動初期化子の継承について:

サブクラスで導入するすべての新しいプロパティにデフォルト値を提供すると仮定すると、次の2つのルールが適用されます。

ルール1サブクラスが指定された初期化子を定義しない場合、サブクラスは指定されたすべてのスーパークラスの初期化子を自動的に継承します。

ルール2サブクラスが、スーパークラスで指定されたすべてのイニシャライザの実装を提供する場合(ルール1に従って継承するか、定義の一部としてカスタム実装を提供することにより)、その後、自動的にすべてを継承しますスーパークラスの便利なイニシャライザ。

これらのルールは、サブクラスがさらに便利なイニシャライザを追加した場合でも適用されます。

だからあなたの質問への答えは次のとおりです:

サブクラスはalwaysスーパークラスの指定された初期化子を呼び出します。イニシャライザを記述せず、コンパイラが文句を言わない場合は、自動イニシャライザ継承を使用しています。イニシャライザを作成しても、関連するアップストリーム(またはサイドストリーム)イニシャライザを明示的に呼び出さない場合は、イニシャライザの最後で自動的に行われます。

さらに、連鎖イニシャライザの動作は2フェーズプロセスです。最初のフェーズでは、サブクラスからスーパークラスに向かって開始し、デフォルト値を任意のパラメーターに割り当てます。 2番目のフェーズでは、プロセスは逆方向に実行されます。スーパークラスで始まり、サブクラスで終わります。ここで、パラメーターのカスタマイズが行われ、オーバーライドされます。

つまり、最初に各init()で変数を設定する必要があります。その後、自由にsuper.init()を呼び出して、カスタムコードを実行できます。したがって、上記のように、スーパーのinitを最初から実行したい場合は、変数の作成直後に「開始」することを検討してください。

class a {
    var name: String

    init() {
        name = "james"
        println("a")
    }
}

class b: a {
    let title: String

    override init() {
        title = "supervisor"
        super.init()
        self.name = "john"
        println("b")
    }
}

let x = b()

これはaを出力し、次にbを出力します。

11
Rikkles

はい、指定されたイニシャライザは委任する必要があるため、super.init()を呼び出す必要があります。 行を記述しない場合、コンパイラーが代わりに行います。

そのため、明示的にsuper.init(...)を記述する必要はありませんが、サブクラスは、カーテンの背後にある場合でもそうでなければなりません。

ただし、最初のフェーズでは、サブクラスでプロパティを設定する必要があり、次にsuper.init()を呼び出す必要があることに注意してください。 2番目のフェーズでは、継承されたすべてのプロパティを変更できます。 super.init()はフェーズ1とフェーズ2の間の完全な区切り文字だと思います。

ドキュメントから:

安全チェック2

指定された初期化子は、継承されたプロパティに値を割り当てる前にスーパークラスの初期化子に委譲する必要がありますそうしない場合、指定された初期化子が割り当てる新しい値は上書きされます独自の初期化の一部としてスーパークラスによって。

4
Binarian

スーパーに電話する必要はないと思います。私は次のように状況をシミュレートしようとしました:

class Animal {
}

class Parrot: Animal {

    override init() {
        // Some code (super not called)
    }
}

ただし、Objective-Cで行うように、実際のアプリでは常にsuper.initを呼び出すことをお勧めします。

0
Evgeniy Kleban