init内でself.viewを参照してはいけない

LINEで送る
Pocket

NSObjectの代表的なメソッドinit。

このメソッドをオーバーライドして、インスタンス生成時に一度だけやる事を書く場面は多いでしょう。


UIViewControllerやそのサブクラスはUIViewのインスタンスを保持していて、self.viewと言う形でアクセスできます。
これらのクラスのサブクラスを作る事は多々あると思います。

そこで一つ気を付けたいのが今回の記事の内容。

initメソッド内でself.viewを参照すべきではない


結論から先に述べますと、viewのライフサイクルが変わってしまい、通常とは違う動作を行います。

じゃぁ、どうすれば良いのか?


init内では、インスタンスの生成にとどめましょう。
frameに関わる変更はloadViewやviewDidLoad以降のメソッドで行う様にする。

これだけです。

それでは、詳細を見て行きましょう。

通常の動作の確認。


まず、通常のライフサイクルを簡単に確認しましょう。


これの実行結果は以下です。

init
label instantiated!
loadView
viewDidLoad

予想通りの結果です。


では、init内でself.viewを参照するとどうなるか。


init内を以下の様に変更します。
(loadView、viewDidLoadは変更しません。)

結果はこちらです。

init
loadView
viewDidLoad

label instantiated!

先にloadView及びviewDidLoadが走ってしまう事が確認出来ます。

どう言う場合に悲惨な事が起こるか


例えば、このUIViewControllerは生成後に何らかのUINavigationControllerのインスタンスにpushViewController:animatedされるとしましょう。


の様な形ですね。

そして、このTestViewControllerのインスタンスのviewDidLoadでself.navigationControllerを参照したいとしましょう。

通常時

先ほどの正しく動くソースのviewDidLoadを以下の様に変更します。


self.navigationControlerを新たに参照する様に追加しています。

実行結果は以下です。

init
label instantiated!
loadView
viewDidLoad
self.navigationController TestNavigationController: 0x75ad3a0

正しくUINavigationControllerのインスタンスが参照出来ています。


問題のソースコードでは


問題のソースコードのviewDidLoadを同じ様に変更した実行結果です。

init
loadView
viewDidLoad
self.navigationController (null)
label instantiated!

navigationControllerが参照出来ていません。

それもそのはず。

initメソッド内でTestViewControllerのviewDidLoadが参照されてしまっているため、まだこのインスタンスはUINavigationControllerのスタックに積まれていないためです。


と言う事で、init内ではself.viewは参照しない様にするのが懸命でしょう。

誰かのお役に立てば。

LINEで送る
Pocket

Dalt

translimit, Inc. Application Engineer. Twitter: @daiki1003 Facebok: Daiki Asahi

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です