1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

UIViewController コードの標準化

Last updated at Posted at 2020-12-28

## はじめに

人それぞれわかりやすいコードの書き方があるとは思うが
毎回違う書き方をしていてはメンテ性も悪いので、ViewControllerのコードを自分なりに標準化したいと思いメモ。

ViewController.swift
import UIKit

class ViewController: UIViewController {
  
  //こ こ で U I の イ ン ス タ ン ス 化
  
  override func viewDidLoad() {
    super.viewDidLoad()
    //viewがメモリに読み込まれた後に一度だけ呼ばれる
    //表示サイクルで1度だけ呼ばれる為クラス内で利用するオブジェクトの初期化などに適する
    //viewに対する追加の初期化処理
    //ネットワーク通信
    //一度だけ行う処理
  }
  
  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    //viewが表示される直前に呼ばれる(初回表示以外にもバックグラウンド復帰、タブ切り替えなど)    
    //UIを非表示や非活性にする処理
    //アプリの状態に応じたviewの更新
    //まだviewが確定されていない為、計算コストの高い処理は避ける
  }
  
  override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    //superViewのboundsが変更される直前に呼ばれる(デバイスの向きが変わるなど)
    //safeAreaはviewWillLayoutSubviewsが一番早く取れるタイミング
  }
  
  override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    //subViewのレイアウトが完了した際に呼ばれる(viewのboundsが確定される)
    //viewのサイズを用いた処理

    //viewの配置メソッドの実行
    setupViews()
  }
  
  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    //viewが画面に表示された直後に呼ばれる(バックグラウンド復帰時やタブ切り替え時など複数回呼ばれる)
    //UI表示が完了しているので、UI表示に関係のない処理を実行するのに適する(ログ送信など)
    //CoreDataへのデータの書き込み
    //アニメーションや動画の再生
  }
  
  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    //viewが取り除かれる直前に呼ばれる(Modal,Push遷移)
    //ViewControllerでの変更の保存など
  }
  
  override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    //viewが取り除かれた直後に呼ばれる(Modal,Push遷移)
    //通知の解除など(iOS9以降は自動解除)
  }
  
  func setupViews(){
    //viewの配置メソッド(viewDidLayoutSubviewsで実行)

    //safeAreaの取得
    let safeArea = view.safeAreaInsets

    //こ こ で U I の サ イ ズ 、 位 置 の 設 定
  }
}

// MARK: - delegateメソッド
extension ViewController : UITextFieldDelegate{
  //delegate毎にextensionで区切って設定
}

## 参考にさせていただきました
UIKitのView表示ライフサイクルを理解する
https://qiita.com/shtnkgm/items/f133f73baaa71172efb2

ViewControllerのライフサイクル
https://medium.com/@shiba1014/viewcontrollerのライフサイクル-37151427bda5

【swift】viewDidLayoutSubviews、layoutSubviews
https://scleapt.com/swift_viewdidlayoutsubviews/

本記事の内容に差し支える点がある場合はご連絡ください。

## 最後に(戯言)
私のような個人開発の素人の場合、書籍やインターネットを参考にしながら何とか動く様にコーディングをするしか無いけど、
やはり、参考にさせて頂く書籍や記事によって同じことを解説していてもコードの考え方が違ったりしていて、混乱をきたしてしまうのがプログラミングの敷居の高い一因なんだろうなと感じる。
その混乱を最小限にするためにも基礎が大事なんだろうなと思った。

アドバイス大歓迎です

## 全コード

ViewController.swift
import UIKit

class LineViewController: UIViewController {
  
  let lineNoLabel = UILabel()
  let lineNoTF = UITextField()
  let doneButton = UIButton()
  
  //viewがメモリに読み込まれた後に一度だけ呼ばれる
  override func viewDidLoad() {
    super.viewDidLoad()
    //用途:ViewControllerの表示サイクルで1度だけ呼ばれる為クラス内で利用するオブジェクトの初期化などに適する
    //・viewに対する追加の初期化処理
    //・ネットワーク通信
    //・一度だけ行う処理
    
    //lineNoLabelの設定
    lineNoLabel.text = "Line No"
    view.addSubview(lineNoLabel)
    
    //lineNoTFの設定
    lineNoTF.delegate = self
    lineNoTF.borderStyle = .roundedRect
    view.addSubview(lineNoTF)
    
    //doneButtonの設定
    doneButton.backgroundColor = .magenta
    doneButton.setTitle("Done", for: .normal)
    doneButton.addTarget(self, action: #selector(doneTaped), for: .touchUpInside)
    view.addSubview(doneButton)
    
  }
  
  //viewが表示される直前に呼ばれる(初回表示以外にもバックグラウンド復帰、タブ切り替えなど)
  override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    
    //UIを非表示や非活性にする処理
    //アプリの状態に応じたviewの更新
    //まだviewが確定されていない為、計算コストの高い処理は避ける
    
  }
  

  
  //superViewのboundsが変更される直前に呼ばれる(デバイスの向きが変わるなど)
  override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    
    //safeAreaはviewWillLayoutSubviewsが一番早く取れるタイミング
    print("SafeArea=",view.safeAreaInsets)
    
  }
  
  //subViewのレイアウトが完了した際に呼ばれる(viewのboundsが確定される)
  override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    
    //viewのサイズを用いた処理
    //viewの配置メソッドの実行
    setupViews()

  }
  
  
  //viewが画面に表示された直後に呼ばれる(バックグラウンド復帰時やタブ切り替え時など複数回呼ばれる)
  override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    print("viewDidAppear")
    //UI表示が完了しているので、UI表示に関係のない処理を実行するのに適する(ログ送信など)
    //CoreDataへのデータの書き込み
    //アニメーションや動画の再生
    
  }
  
  
  //viewが取り除かれる直前に呼ばれる(Modal,Push遷移)
  override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    //ViewControllerでの変更の保存など
  }
  
  override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(animated)
    //通知の解除など(iOS9以降は自動解除)
  }
  
 
  func setupViews(){
    
    //safeAreaの取得
    let safeArea = view.safeAreaInsets
    
    //UIパーツの配置エリアの大きさ
    let partsArea_W = view.frame.width - safeArea.left - safeArea.right
    let partsArea_H = view.frame.height - safeArea.top - safeArea.bottom
    
    //UIパーツ間の間隔
    let margin_X = round(partsArea_W * 0.05)
    let margin_Y = round(partsArea_H * 0.05)
    
    //共通で使用するパーツの高さ幅など
    let partsHeight = round(partsArea_H * 0.05)
    let partsWidth = partsArea_W - margin_X * 2
    let buttonHeight = round(partsArea_H * 0.05)
    
    //lineNoLabelのサイズ、位置の設定
    let lineNoLabel_W = partsWidth
    let lineNoLabel_H = partsHeight
    let lineNoLabel_X = safeArea.left + margin_X
    let lineNoLabel_Y = safeArea.top + margin_Y
    lineNoLabel.frame.size = CGSize(width: lineNoLabel_W, height: lineNoLabel_H)
    lineNoLabel.frame.origin = CGPoint(x: lineNoLabel_X, y: lineNoLabel_Y)
    
    
    //lineNoTFのサイズ、位置の設定
    let lineNoTF_W = partsArea_W - margin_X * 2
    let lineNoTF_H = partsHeight
    let lineNoTF_X = safeArea.left + margin_X
    let lineNoTF_Y = lineNoLabel.frame.maxY
    lineNoTF.frame.size = CGSize(width: lineNoTF_W, height: lineNoTF_H)
    lineNoTF.frame.origin = CGPoint(x: lineNoTF_X, y: lineNoTF_Y)
    
    
    let doneButton_W = partsArea_W - margin_X * 2
    let doneButton_H = buttonHeight
    let doneButton_X = safeArea.left + margin_X
    let doneButton_Y = view.bounds.height - safeArea.bottom - doneButton_H - margin_Y
    doneButton.layer.cornerRadius = doneButton_H / 2
    doneButton.frame.size = CGSize(width: doneButton_W, height: doneButton_H)
    doneButton.frame.origin = CGPoint(x: doneButton_X, y: doneButton_Y)
    
  }
  
  //doneButtonが押されたときに呼ばれるメソッド
  @objc func doneTaped(){
    print("done")
    
    //画面遷移
    performSegue(withIdentifier: "goInput", sender: nil)
    
  }
}

// MARK: - UITextFieldDelegate

extension LineViewController : UITextFieldDelegate{
  
  //textFieldでReturnが押されたときに呼ばれる
  func textFieldShouldReturn(_ textField: UITextField) -> Bool {
    
    //キーボードを閉じる
    textField.resignFirstResponder()
  }
  
  //textFieldの編集が終わったときに呼ばれる
  func textFieldDidEndEditing(_ textField: UITextField) {
    
    guard let text = textField.text else { return }
    print(text)
    
  }
}
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?