「super.init()の前でプロパティを初期化するのはなぜ?」
・・・指定イニシャライザに関して理解できていない証拠なのでまとめてみました。
■指定イニシャライザ(Designated Initializer)とは
「Designated initializers are the primary initializers for a class. A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.」
訳:
「指定イニシャライザは、クラスの主な初期化子です。指定イニシャライザは、そのクラスによって導入されたすべてのプロパティを完全に初期化し、適切なスーパークラスイニシャライザを呼び出して、スーパークラスチェーンの初期化プロセスを続行します。」
※引用:The Swift Programming Language (Swift 4.1): Initialization
初期化プロセスってなんだろう?
■初期化プロセスとは
「Class initialization in Swift is a two-phase process. In the first phase, each stored property is assigned an initial value by the class that introduced it. Once the initial state for every stored property has been determined, the second phase begins, and each class is given the opportunity to customize its stored properties further before the new instance is considered ready for use.
The use of a two-phase initialization process makes initialization safe, while still giving complete flexibility to each class in a class hierarchy. Two-phase initialization prevents property values from being accessed before they are initialized, and prevents property values from being set to a different value by another initializer unexpectedly.」
訳:
「Swiftのクラス初期化は2段階プロセスです。第1段階では、格納された各プロパティには、導入されたクラスによって初期値が割り当てられます。各格納されたプロパティの初期状態が決定されると、第2段階が始まり、新しいインスタンスが使用可能とみなされる前に各クラスに格納されたプロパティをカスタマイズする機会が与えられます。
2段階の初期化プロセスを経ることによって、クラス階層内の各クラスに完全な柔軟性を与えながら、初期化を安全に行うことができます。2フェーズ初期化は、プロパティ値が初期化される前にアクセスされるのを防ぎ、予期せず別のイニシャライザによってプロパティ値が別の値に設定されるのを防ぎます。」
「The class instance is not fully valid until the first phase ends. Properties can only be accessed, and methods can only be called, once the class instance is known to be valid at the end of the first phase.」
訳:
「クラスのインスタンスは、初期化プロセスの第1フェーズが終了するまで一切無効です。クラスのインスタンスは、初期化プロセスの第1フェーズが有効であると判別された時のみ、プロパティにのみアクセスでき、メソッドを呼び出すことができます。」
※引用:The Swift Programming Language (Swift 4.1): Initialization
初期化プロセスは2段階になっており、このプロセスを経ることによって別のイニシャライザが意図しない別の値に設定するのを防いでいるんですね。
■具体的な初期化プロセスの事例を考えてみる
初期化の2段階プロセスに関して事例を考えてみます。
以下コードは、NSObjectをスーパークラスとするサブクラス「Alert」です。
指定イニシャライザが呼び出される。
↓
サブクラス「Alert」の指定イニシャライザは、「Alert」によって導入されたすべての格納されたプロパティが値を持つことを確認した上で、プロパティのメモリを初期化。
↓
指定イニシャライザは、スーパークラス「NSObject」のイニシャライザに渡され(super.init()でアクセス)、自身の格納された他のプロパティーに対して同じタスクを実行。「NSObject」に格納されたプロパティのすべてが値を持つことが保証できた場合、インスタンスのメモリは完全に初期化されたとみなされ、フェーズ1は完了。
第2フェーズとして、プロパティへのアクセスとプロパティの変更、インスタンスメソッドの呼び出しなどが可能になる。
初期化のプロセスに沿って考えれば、「super.init()の前でプロパティを初期化するのはなぜ?」という疑問も解消できますね。
■最後に
私のように指定イニシャライザに関してまだ明確に理解できていない方の参考になればと思い記事を書きましたが、もし内容に誤り等あればご指摘いただけますと幸いです。
■参考
・The Swift Programming Language (Swift 4.1): Initialization
・Swiftでsuper.init()前にプロパティを初期化しなければいけない理由 - 面白きことは良きことなり