iOSのレイアウトサイクル勉強した

会社の先輩の記事と、Appleのドキュメントを読みながら学習した。 speakerdeck.com

iOSのレイアウトサイクルをなぜ知らなければいけないか。

1. 重たいから

意図しない描画を引き起こさないために。

2. 思い通りにレイアウトさせるため

設定はしたもののサイクルが回らなかったせいで見た目が想定と違うことを防ぎたい。

レイアウトサイクル

1. loadView()

viewプロパティが必要になった時に呼ばれる。viewがIUO型で宣言されているので、viewがアクセスされる前に初期化させるものと思う。 IB使ってる時はオーバーライドしてはいけない。 コードレイアウトの時など、Viewを自分で作るときはオーバライドする。 そこで、ViewControllerのviewプロパティを設定する。

2. viewDidLoad()

VCがViewヒエラルキーをメモリにロードした後に呼ばれる。 Viewヒエラルキーがnibから読まれたか、コードでloadView()をオーバライドしたかは気にしない。

nibから読み込んだviewsのAttributes設定などによく使う。

3. viewWillAppear()

自身のviewがviewヒエラルキーに追加される直前なのを通知する。

4. viewWillLayoutSubviews()

VCが自身の子viewsを描画する直前に呼ばれる。 子Viewのboundsが変わった時、VCのviewがsubviewsの位置を調整する。 VCが子Viewsをレイアウトする前に処理をはさみたいならここをオーバライドする。デフォルトでは何もしない。

5. layoutSubviews()

サブビューを描画する。 より精密な子viewsのレイアウトをするためにオーバーライドする。 このメソッドはautoresizingと制約ベースの挙動が自分の意図した動きを提供しないときのみオーバーライドすべき。 frameの設定は直にしろ。

6. viewDidLayoutSubviews()

VCが自身の子viewsを描画した直後に呼ばれる。 ビューコントローラのビューのboundsが変更されると、そのビューはサブビューの位置を調整し、システムはこのメソッドを呼び出す。

7. viewDidAppear()

自身のviewがviewヒエラルキーに追加される直後なのを通知する。 super絶対呼べ。 ポップオーバーなどでVC表示をしていて、前面のVCをdissmisしても後面のVCのviewDidAppear()は呼ばれない。

8. viewWillDisappear()

Viewヒエラルキーから自分が取り除かれる直前に呼び出される。

9. viewDidDisappear()

iewヒエラルキーから自分が取り除かれた直後に呼び出される。

レイアウトループ

以下のようなレイアウトループがずっと走ってる。 f:id:thunder-runner:20180610213712p:plain

レイアウトが必要かどうかのフラグが立つ条件

  • setNeedsLayout()を呼び出す
  • バイスが回転した
  • 子ビューが追加や削除をした
  • 子ビューがスクロールした
  • 子ビューのframeやtransformが変化した などなど。らしい

setNeedsLayout()はフラグを立てるだけなので、レイアウト自体は次のレイアウトループ

レイアウト関連のメソッド

setNeedsDisplay()

UIViewにレイアウトフラグを設定する。

setNeedsLayout()

UIViewのサブビュー全てにレイアウトフラグを設定する。

layoutIfNeeded()

呼ばれた時に、viewとviewをルートとしたサブビューに画面更新の必要があった場合に全て即座に配置する。 フラグの設定でなくて、強制再描画なので処理が重い。