Swift で,構造体やenum,クラスにおいて,初期化が失敗しうるコンストラクタを利用したい時には,Failable Initializer を利用すれば良いらしいのだが,これをクラスで利用しようとしたらハマったのでメモ.
Failable Initializer とは
初期化に失敗したことを,nil
を返すことで伝えることのできるイニシャライザ.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
これで,初期化がうまくいかなかった場合には,nil
が返される.
ハマったこと
やろうとしたことは,コンストラクタ内で例外を扱うことで,具体的には以下のような感じ.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
ところが,このように記述すると,return nil
の位置で以下のようなエラーが発生する.
1
|
|
同じことでハマった人がいるらしい.
結論から言うと,値型である構造体や列挙型ではいかなるタイミングでも初期化を失敗(return nil
)できるが,クラスについては,すべての stored property が明示的に初期化された後でなければ初期化を失敗させることができないらしい.
A failable initializer for a value type (that is, a structure or enumeration) can trigger an initialization failure at any point within its initializer implementation. In the Animal structure example above, the initializer triggers an initialization failure at the very start of its implementation, before the species property has been set.
For classes, however, a failable initializer can trigger an initialization failure only after all stored properties introduced by that class have been set to an initial value and any initializer delegation has taken place.
The Swift Programming Language (Swift 2.1): Initialization
動作を確認してみる
Playground でサンプルコードを動かして動作を確かめてみる.
まずは,構造体の場合.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
次に,クラスの場合.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
公式ドキュメント曰く,stored property である name は String!
として宣言する.すると,デフォルト値として nil
が格納されるが,初期化成功時には,stored property が nil かどうかを気にせずにアクセスしたい.(stored property に対する nil チェックが必要ないようにしたい)ので,クラスでは全ての stored property を初期化してから return nil する必要があるそうだ.
でも,コンストラクタの返り値が nil であったならどちらにしろプロパティにアクセスはしないわけで,なぜ全プロパティを初期化してから nil を返す必要があるのか,いまいちわからなかった.