面白きことは良きことなり

拙く未熟なiOSエンジニアの備忘録と戯言

Swiftでsuper.init()前にプロパティを初期化しなければいけない理由

前提

Swiftで独自クラスを作成してinitメソッドを書く時、
この独自クラスが持つプロパティの初期化をsuper.init()の後に行って
エラー( Property 'self.property' not initialized at super.init call )に会う人は少なからずいると思う。
f:id:aryzae:20170306014641p:plain

Objective-Cでは、これで問題なかったので、同じ様に書く人は自分以外にもいそう。
そしてエラー内容の言われるがまま、super.init()の前にプロパティの初期化を書いてエラーを回避するのだけれど、そもそもエラーになる理由をわかっていなかったので調べた。

結論

developer.apple.com
AppleのThe Swift Programming LanguageにあるInitializationで記載されていました。
Two-Phase InitializationのNOTEにこう書かれています。

Swift’s two-phase initialization process is similar to initialization in Objective-C. The main difference is that during phase 1, Objective-C assigns zero or null values (such as 0 or nil) to every property. Swift’s initialization flow is more flexible in that it lets you set custom initial values, and can cope with types for which 0 or nil is not a valid default value.

スタジオガラゴさんから同じ箇所の日本語を引用すると

Swift の 2 段階の初期化処理は、Objective-C での初期化に似ています。主な違いはフェーズ 1 で、Objective-C ではすべてのプロパティにゼロまたは null 値(0 または nil)を代入します。Swift の初期化フローは、初期値を変更できるためより柔軟で、0 や nil が有効なデフォルト値ではない型を扱うことができます。


大雑把に自分の解釈も含めて要約すると、Objective-Cの時は自動でプロパティに0とかnilが入ってて問題なかったけど、
Swiftはnilが入らない型とかあるし自動で値入れられないから、初期値いれといてねって話。


まとめると

  • 初期化処理は2段階で行われる
  • Objective-Cの初期化
    • 1段階目([super init]の以前):すべてのプロパティにデフォルト値として0かnilが入る
    • 2段階目([super init]の後):ユーザーによる初期化
  • Swiftの初期化
    • 1段階目(super.init()の以前):プロパティにデフォルト値を入れる必要がある(non-optional型の時、nilがデフォルト値として入らないことによる設計と思われる)
    • 2段階目(super.init()の後):ユーザーによる初期化