【iOS】iOSアプリ開発入門~ 画面ライフサイクル編~

# はじめに
前回はプッシュ、タブ遷移の実装方法についてお話しました。
画面遷移編３：https://qiita.com/euJcIKfcqwnzDui/items/c0c0ccbd8d301b96d8b7

今回は画面ライフサイクル編としていまして、画面がどのように制御されているのかを説明します。
アプリを理解する上で外せない内容です。
OSや開発環境などによって変わり、例えばiOSとAndroidでは少し異なったりします。
なので新しいOSのアプリ実装に取り掛かる際はまずこの**ライフサイクル**を理解するところから始めます。

とはいえそれほど難しい内容ではありません。
それでは説明していきます。

# ライフサイクルとは
オブジェクトがいつ生成され、いつ解放されるのか、生存中はどのようなイベントを起こすのかというような意味です。
そのオブジェクトが生まれてから死ぬまでの間というくらいの認識でいいかなと思います。

アプリで画面のライフサイクルと言われたら、画面はいつ生成されるのか、レイアウトはいつ決定されるのか、その時どんなイベントがメソッドとして呼ばれるのかというような意味です。
特にそのライフサイクルの中でどのメソッドがどのイベントで呼ばれるのかが重要になります。

# 画面(UIViewController)のライフサイクル
アプリでまず最初に注目するのが画面ライフサイクルのイベントです。

そのライフサイクルイベントは`UIViewController`で定義されています。
プロジェクトを初めて作ったときに`ViewController`クラスが予めテンプレートとして準備されていました。
その中に`override func viewDidLoad() {}`というメソッドが１つ定義されていました。
これはライフサイクルイベントのメソッドの１つで、`viewDidLoad`は「画面の読み込みが完了した」というイベントで呼ばれるメソッドです。
このようなイベント毎に呼ばれるメソッドがいくつかあるので紹介していきます。

先に紹介しておくと以下のようなイメージです。
<img width="655" alt="ライフサイクル全体図.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326173/62c33c70-8523-52d7-b2d3-1d3a835baadb.png">

## 画面読み込み時のライフサイクルイベント
`UIViewController`がメモリに確保されるときに呼ばれるライフサイクルイベントです。
新しくインスタンスが生成されるときのみ、つまり初回表示時に１回だけ呼ばれるイベントで、例えばプッシュ遷移の戻るで表示されたとき画面インスタンスは新しく生成されないためコールされません。

### loadView()
画面が読み込まれるときにコールされるイベントです。
あくまで紹介のいう意味で載せていますが、基本的にはここに処理は書いてはいけません。

### viewDidLoad()
画面の読み込みが完了したときに呼ばれるイベントです。
画面に配置しているラベルなどのサブビューの初期化は一般的にここで行ないます。
このメソッドがコールされるタイミングではアプリではまだこの画面は表示されていません。
ここで時間のかかる処理を行ってしまうと、アプリ上に画面が表示されるまでその分時間がかかってしまいます。

## 画面表示時のライフサイクルイベント
画面が表示されるときに呼ばれるライフサイクルイベントです。
画面遷移が発生すると必ず呼ばれるイベントで、戻るで表示されたときであっても呼ばれます。
### viewWillAppear(_ animated: Bool)
画面が表示される直前に呼ばれるイベントです。
これが呼ばれるタイミングではまだ画面は表示されていません。
表示される度に毎回実行したい処理はここに書きます。

### viewDidAppear(_ animated: Bool)
画面遷移が完全に完了したときに呼ばれるイベントです。
呼ばれたタイミングではすでにこの画面は表示されています。
すでに画面が表示されたときに呼ばれるのでラベルなどの初期化をここで行うと初期化前の状態が一瞬表示されるので少しおかしなことになります。

## 画面非表示のライフサイクルイベント
画面が非表示となるときに呼ばれるイベントです。
次の画面、前の画面に遷移する前に必ず呼ばれるメソッドです。
### viewWillDisappear(_ animated: Bool)
画面非表示となる直前で呼ばれるイベントです。
直前なのでまだこの画面は表示されています。
### viewDidDisappear(_ animated: Bool)
画面非表示となった直後に呼ばれるイベントです。
ここが呼ばれたタイミングではすでに次or前の画面への遷移は完了し、この画面は表示されていません。

# ライフサイクルイベントメソッドの書き方
ライフサイクルイベントは親クラスである`UIViewController`に定義されたメソッドです。
それぞれのイベントに処理を書くためにはこの親クラスのメソッドを上書きしてあげる必要があります。
上書きするためにはメソッドの前に`override`とつけます。

以下は実装例です。
画面クラスの中に実装して実行すると、それぞれのイベントが発生したタイミングでログが表示されるのでシミュレータで実行してください。

```swift:SampleViewController.swift
class SampleViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 画面初期化処理を書く
        print("画面のロード完了")
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // 画面表示前の処理を書く
        print("画面表示直前")
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // 画面表示直後の処理を書く
        print("画面表示直後")
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // 画面非表示直前の処理を書く
        print("画面非表示直前")
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        // 画面非表示直後の処理を書く
        print("画面非表示直後")
    }
}
```
メソッドの中で最初に`super.メソッド名`という呼び出しをしています。
`super`は親クラスを表します。
`super.メソッド名`とすると親クラスに書かれている処理を呼び出します。
とりあえずはライフサイクルイベントの最初は必ず`super.メソッド名`と書かなければいけないと覚えておくだけで構いません。

# イベントの呼ばれる順序
[冒頭](#画面(UIViewController)のライフサイクル)で図を書いたようなイメージで呼ばれていきます。
１つの画面に対象を絞ると以下のような順序で呼ばれます。

- 画面を生成し表示する場合(例：segueで遷移されたとき)
 1. `viewDidLoad`
 2. `viewWillAppear`
 3. `viewDidAppear`
- 生成済みの画面を表示する場合(例：プッシュで表示していた画面から戻るで遷移されたとき)
 1. `viewWillAppear`
 2. `viewDidAppear`
- 画面が非表示になる場合
 1. `viewWillDisappear`
 2. `viewDidDisappear`

もう少し具体的な例をあげて順序を示します。
`First`,`Second`という画面があると仮定しプッシュ遷移で遷移していくとします。

- アプリを起動し`First`が表示されるとき
 1. `First.viewDidLoad`
 2. `First.viewWillAppear`
 3. `First.viewDidAppear`
- `First`から`Second`に画面遷移するとき
 1. `First.viewWillDisappear`
 2. `Second.viewDidLoad`
 3. `Second.viewWillAppear`
 4. `First.viewDidDisappear`
 5. `Second.viewDidAppear`
- `Second`から`First`に戻るとき
 1. `Second.viewWillDisappear`
 2. `First.viewWillAppear`
 3. `Second.viewDidDisappear`
 4. `First.viewDidAppear`

※上記はおおよそのイメージとして捉えてください。
例えば「`First`から`Second`に画面遷移するとき」の「1. `First.viewWillDisappear`」と「2. `Second.viewDidLoad`」はほぼ実際には同時に呼ばれています。

# 最後に
今回は`UIViewController`のライフサイクルイベントについて紹介しました。
実際にシミュレータで実行して画面遷移してみないとイメージが付きづらいかもしれないので試してください。

さて、今回の投稿で「iOSアプリ開発」の入門編は終了です。
ここまででiOSアプリの基本的なUIの配置方法や画面遷移の方法について紹介してきました。
単純にいうとあとはここにSwiftのコーディングを混ぜて処理をさせていくだけです。
Swiftコーディングについては別途投稿していますので、以下URLからたどってください。

次回からは初級編としてリスト表示など、もう少し複雑なUIの作成方法などについて紹介していければと思います。

本連載ではプログラミング未経験からiOSアプリ開発が行えるようになることを目的としています。
今までの投稿をまとめていますのでこちらもご覧ください。
http://naoyalog.com/