Kekeの日記

エンジニア、読書なんでも

LifecycleとUIのヒエラルキーを抑える

はじめに

前回の記事で、iOSアプリのレイアウトを決める方法として、Auto Layoutを紹介しました。

www.1915keke.com

Auto Layoutの中でも、StoryBoardからInterface Builderを使って設定する方法、.xibに書く方法、コードから直接指定する方法があったのですが、宣言的にコードとしてという観点からコードで書くことにしました。

とりわけ、StoryBoardのGUIから指定する方法が宣言的ではないと言っているわけではないですが、コードとしてViewControllerに書いた方が真っ当でしょう。

今回はAutoLayoutに重要なViewだったり、Safeareaなどを調べ、制約とどのような関連があるかを学べられるといいなと思います。

ViewControllerのライフサイクル

まず、Viewがどのように生成されて、部品がマウントされて、削除されるのかを知る必要があります。

これはいつ、どのような制約をかければいいかに繋がってきます。

アプリ開発をしていると以下のような状況にしばし、直面します。

  • Viewのレイアウトが崩れてる
  • なんかカクカクする
  • チラつく部品がある

このような問題はViewのライフサイクルを理解せずにコードを書いていることが原因のことが多々あります。

Viewのライフサイクルの中で与えられるメソッドは以下の通りです。

image.png

ここでViewが読み込まれる時に何が起きるかを解説しまう。

viewDidLoad

Viewがライフサイクルに取り込まれてからをこのメソッドを使うことができる。 Viewがロードされると呼び出される。ユーザーが見えるようになるまでにデータを揃えたりするのに使える

参考文献にあるこの関数でするべきものは

  • ネットワークコール
  • UIを構築
  • 他のタスクを走らせる

です。私の場合は

        self.view.addSubview(imageView)

        // MARK: - Inputs
        
        self.emailTextField.textColor = UIColor.black
        self.passwordTextField.textColor = UIColor.black
        self.emailTextField.placeholder = "Email"
        self.passwordTextField.placeholder = "Password"
        self.view.addSubview(emailTextField)
        self.view.addSubview(passwordTextField)
        
        // MARK: - Button

        self.button.setTitle("SIGN IN", for: UIControlState.normal)
        self.button.backgroundColor = UIColor.black
        button.addTarget(self, action: #selector(signinPressed(_:)), for: UIControlEvents.touchUpInside)
        self.view.addSubview(button)

のようになっています。

viewWillAppear このメソッドはViewが見えるようになる直前に呼び出される。 この時は、Viewは作成されているのですが、まだマウントされていません。

このメソッドは、オーバーライドすることでViewのオブジェクトを見せたりするかしないかのフィルタリングなどに使うことができます。

viewWillLayoutSubviews デフォルトでは何もしない。もしViewの枠が変わればサブビューも配置を変えるが、そのメソッドに変更を加えることができる

viewDidLayoutSubviews Subviewを調整したあとに呼び出される。 Subviewが調整し終わった後に何かをしたい時オーバーライドするべき。

たとえば、ViewControllerの表示、画面の向きなどの変更のときなのです。

viewDidAppear Viewが見えたあとに呼び出される。 一般的には、Coredataへデータを保存したり、アニメーションなどを開始たり、ネットワークからデータを集め始めたりする

viewWillDisappear viewの階層から取り除かれるときに呼び出される。 状態を保存するにはするには最適である

viewDidDisappear viewが階層から取り除かれたときに呼び出される。

Viewアーキテクチャの基礎

ライフサイクルを理解したところでアーキテクチャを学ぼうと思います。

簡単な例だと以下のようなアーキテクチャになっています。

image.png

もっとも開発者の関心があることはUIを見せるUIViewクラスだと思います(とそれを継承したクラス)。

ここで階層的に定義される親ビューをsuperviewで、子ビューはsubviewと呼ばれます。

階層状になっており、

  • スクリーン
  • ウィンドウ
  • ビュー

の状態です。

UIWindow、UIScreenとは

UIWindowはViewを管理して、ディスプレイに表示する「窓」としての役割を果たします

また、UIScreenとは一言でいうと画面自体のことです。

ウィンドウは複数開くことができて、キーボードを使う時などもウィンドウが出てきてます。

ではUIViewとCALayerとは

もっとも参考になったのは以下の記事です。

stackoverflow.com

UIViewは描画を行うクラスのことである。

そしてCALayerは例えばマスクの情報など描画する内容を管理するもので、UIViewを使うと必ず使っていることになる。 使うときはUIViewだけでは設定できないようなアニメーションなどを使いたい時です。

まとめ

ライフサイクルやスクリーン、ビューを知ることで、何をどこに書くかがより明瞭になった気がします。

余談

肥大化するviewDidLoadをベストプラクティス

この記事でも紹介したようにviewDidLoadがかなりすることが大きく、コードが肥大化するケースがあります。

以下の記事でベストプラクティスが紹介されてありました。

blog.penginmura.tech

再度、掲載します。

        self.view.addSubview(imageView)

        // MARK: - Inputs
        
        self.emailTextField.textColor = UIColor.black
        self.passwordTextField.textColor = UIColor.black
        self.emailTextField.placeholder = "Email"
        self.passwordTextField.placeholder = "Password"
        self.view.addSubview(emailTextField)
        self.view.addSubview(passwordTextField)
        
        // MARK: - Button

        self.button.setTitle("SIGN IN", for: UIControlState.normal)
        self.button.backgroundColor = UIColor.black
        button.addTarget(self, action: #selector(signinPressed(_:)), for: UIControlEvents.touchUpInside)
        self.view.addSubview(button)

これをViewControllerのextentionとして定義します。 ここではsetEmailTextFieldだけやってみようと思います。

override func viewDidLoad(){
     super.viewDidLoad()

      ...

      setEmailTextfield()

      ...
}

extention HogeViewController{
     private func setEmailTextField(){
          ...

           self.emailTextField.placeHolder = "Hello hoge"
           self.view.addSubView(emailText Field)
}

参考記事

qiita.com

qiita.com

developer.apple.com

ios ViewとLayerの関係 | Tech Blog | 株式会社INDETAIL - インディテール