Edited at

ビューコントローラの生成から表示までのライフサイクルと、タイミングごとに適した処理まとめ

More than 3 years have passed since last update.


記事起こしのきっかけ

書籍「よくわかるAuto Layout」を1周しました。

メモリにとって効率の良いビューの取り扱い方などなど

あれこれ目から鱗の情報があった中でも、特に今までもやもやしてたことがすっきりした気分になった

ビューコントローラが表示されるまでのライフサイクルと

各タイミングで行うのに最適な処理について咀嚼した結果を書き残しておきます。

なお、解釈がずれてるなどおかしな点がございましたらご指摘いただけると嬉しいです。


ViewController生成~読み込み(1回しか呼ばれない)


loadView()

 ビューをメモリに載せつつ、メモリの載せた先(ポインタ)とビューの情報を関連付けるメソッド。

 Storyboardを使用している場合は、Storyboad上で設定しているレイアウト以外に

 何か特別な初期処理をしなくてはいけない場合以外はオーバーライドする必要がない。

 もしソース上でビューを生成する場合はこれをオーバーライドして処理を書くが、

 普段通りオーバーライドするノリでsuper.loadView()を呼ぶと

 self.viewが余分に1個生成されてしまうので呼ばない方がメモリを食わない。


viewDidLoad()

  上記のloadView()完了時に呼ばれる、ビューコントローラが生成された直後に呼ばれるメソッド

 オーバーライドして利用。

※上記、正しくは「ビューがロードされた直後に呼ばれる」でしたので、訂正いたします。

 なお、書籍にもビューが読み込み完了後に呼ばれると記載があったので、私個人の解釈が誤ってました。

 生成後とロード後の違いの解説も含め、dokunekoさんよりご指摘いただきました。

 感謝感謝です。ありがとうございました。

最適な処理の例:


  • 生成済みのラベルやビューのプロパティに画面表示時に最初に表示したい値を入れる

  • クラス内で使う変数の類を初期化


表示・レイアウト(条件を満たせば何度でも呼ばれる)


viewWillApper()

 初回にはviewDidLoad()の後に呼ばれる、ビューが画面に表示される直前に呼ばれるメソッド。

 オーバーライドして利用。

 メモリに表示済みの自ビューがあって、その自ビューが画面に表示される直前であればいつでも呼ばれる。

 初回以外にもホーム画面にいって戻ってくるなどのバックグラウンドから画面を復帰して再表示した際や

 UITabControllerのタブ切り替えで戻ってきた際、遷移先の画面から戻ってきた際などに呼ばれる。

 もろもろの表示のための処理が呼ばれる前のタイミングなので、

 動的な値を設定する処理を書くのに向いている。

最適な処理の例:


  • UI~の内容(.textプロパティや.imageプロパティなどなど)を更新し、表示を最新の情報に保つ

  • テーブルビューやコレクションビューの内容を更新(reloadData())し、表示を最新の情報に保つ
     


viewWillLayoutSubviews()

 初回にはviewWillApper()の後に呼ばれる、ビューのレイアウトが開始するときに呼ばれるメソッド。

 オーバーライドして利用。

 初回以外に端末の回転やビューが画面に再表示されたタイミングなど、

 ビューが新しい大きさに変更されたときに必ず呼ばれる。

 表示中一番上の親ビュー(self.view)から見て子ビューのレイアウトが確定していないものの、

 画面の回転方向は確定したタイミング。

 レイアウトについて、このメソッドが呼ばれるタイミングで以下の処理を順番に行なう。

  1. Storyboardなどで設定したマージンや幅・高さ、

   ラベルやテキストの内容などの制約(Constraits)情報を更新する

   (UIViewContollolerのupdateViewConstraitos()を呼ぶ)

  2. 1で更新した制約を元に、親ビューから子ビューへ階層順にUIViewのupdateConstraits()を呼んで

   表示するビューすべてに制約の更新を行き渡らせる

  3. 1,2で更新された制約を元に、フレーム(実際に画面上に表示される見た目の情報)を更新する

   (親ビューから子ビューへ階層順にUIViewのlayoutSubviews()を呼ぶ)

最適な処理の例:


  • ユーザー操作により変更された表示中の値を反映後の状態を元に画面全体のレイアウトを更新する

 ※画面全体に何かしたい場合以外は用事がない気がする。

  特定のビューだけ更新したい場合は、その更新したいビューだけ指定して

  updateViewConstraitos()layoutSubviews()を活用すれば良いのだろうなと思った。

 ※回転後にレイアウト再設定の処理もここに書くこともできなくはないが、

  何せ回転時以外にもたくさん呼ばれるメソッドなので回転時のデリゲートメソッドに仕掛けた方が良い。


viewDidLayoutSubviews()

 viewWillLayoutSubviews()の後に基本セットで呼ばれる、

 ビューのレイアウトが完了したときに呼ばれるメソッド。

 オーバーライドして利用。

 生成したビューコントローラ内すべてのレイアウトが確定し、

 レンダリング(画面への描画処理)する準備が整うタイミング。

最適な処理の例:

書籍に例の記載もなく、特に思いつかなかったので見つかれば更新するかも


viewDidApper()

 viewWillApper()と必ずセットで呼ばれ、初回の場合はviewDidLayoutSubviews()の後に呼ばれる

 ビューが表示された直後に呼ばれるメソッド。

 オーバーライドして利用。

 viewDidLayoutSubviews()で確定したレイアウト情報を元にレンダリングが完了したタイミング。

 ユーザーに見せるための処理はすべて完了しているので、

 アプリが提供するユーザー体験に直接影響のない処理を書くのに向いている。

最適な処理の例:


  • ログの送信

  • Analyticsのタグ情報を送信

  • レビューにご協力お願いします~なポップアップメッセージの表示

  • 最新のバージョンのアプリにアップデートお願いします~なポップアップメッセージの表示