【Swift5】Segueによる画面遷移 (performSegueとprepareの順番)

# はじめに
iOSアプリの画面遷移において、segueを使用する際に、performSegueメソッドとprepareメソッドを使用する。
一般に、prepareの後に、performSegueを使用する。

**prepare(つまり、「準備する」)なのに、これが後に使用**される。
感覚的に、これがしっくりこなかったので、調べてみた。

# 環境
| No |    項目     |   内容    |
|---:|-------------|------------|
| 1  |      OS       |   Mac     |
| 2  |      Swift    |   5.6.1 |
| 3  |      Xcode     |   13.4.1 |

# 結論
performSegueをトリガーに、Segueが開始される。
prepareはSegueの準備するためのメソッドなので、Segueが開始されてから準備し始める。

つまり、**あらかじめ準備してくれるわけではなく、合図がかかってからprepareが動作する。**

# 実装
下記は、[Udemy](https://www.udemy.com/share/101WsW3@3wpyfvGosQ4BoYmrfAquM7xhbfocXbCjwd_Oj1XWjO6SJtp8LKCTxdiL5kvmNeKcYA==/)で勉強している際に出てきた、セクション11: BMI計算アプリのコードである。
これを使って解説する。
```ViewController.swift
    @IBAction func calculateButton(_ sender: UIButton) {
        let height = heightSlider.value
        let weight = weightSlider.value
        calculatorBrain.calculateBMI(height: height, weight: weight)
        // ※指定されたIDに対してSegueを開始
        performSegue(withIdentifier: "goToResult", sender: self )
        // ここに何らかの処理を書くと、④の後、つまりsegueの処理が終了した後に実行される。
        print("画面遷移完了")
    }
    
    // ①セグエ実行前処理
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // ②Segueの識別子確認
        if segue.identifier == "goToResult" {
            // ③遷移先ViewCntrollerの取得
            let destinationVC = segue.destination as! ResultViewController
            // ④値の設定
            
            destinationVC.bmiValue = calculatorBrain.getBMIValue()
            destinationVC.bmiadvice = calculatorBrain.getBMIadvice()
            destinationVC.bmicolor = calculatorBrain.getBMIColor()
        }
    }
```
# ※指定されたIDに対してSegueを開始
```swift:
performSegue(withIdentifier: "goToResult", sender: self )
```
withIdentifier: "goToResult"と設定したsegueのIDに対して実行する。
sender: selfとし、画面遷移元のクラス、つまり現在のクラスを指定する。

**ここからsegueが開始するため、画面遷移に関するなんらかの処理を行うなら、performSegueの前に記述する必要がある！！**

```swift:
// ここに何らかの処理を書くと、④の後、つまりsegueの処理が終了した後に実行される。
print("画面遷移完了")
```
上記の部分に書くと、後述するprepareメソッドに反映できなくなってしまうため注意が必要である。
(筆者はここで、performSegueと計算部分(let height... ~ calculateBrain...)までの順番を入れ替えて書いていたため、後述のprepareの④値の設定に計算結果が反映されなかった。)

# ①セグエ実行前処理
prepareメソッドでsegueの準備をしていく。
```swift:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { ... }
```
ここはデフォルトのまま。

# ②Segueの識別子確認
```swift:
if segue.identifier == "goToResult" { ... }
```
画面遷移先が複数あった場合、どのIDが複数になるため、if文でどのIDに紐づいたSegueを使用するかを決定する。

# ③遷移先ViewCntrollerの取得
```swift:
let destinationVC = segue.destination as! ResultViewController
```
destination: UIViewController
destinationは④で使用するbmiValueプロパティを所持していないため、Result~にダウンキャスティングする。

# ④値の設定
```swift:
destinationVC.bmiValue = calculatorBrain.getBMIValue()
...
```
遷移先で定義しているプロパティ(bmiValue)に値を代入することで、値を渡す。

# 画面遷移先のViewController
最後に、画面遷移先でどのように値を受け取っているのかを記載する。
```swift:
    var bmiValue : String?
    var bmicolor : UIColor?
    var bmiadvice: String?
    
    @IBOutlet weak var bmiValueLabel: UILabel!
    @IBOutlet weak var bmiAdviceLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        bmiValueLabel.text = bmiValue
        bmiAdviceLabel.text = bmiadvice
        view.backgroundColor = bmicolor
    }
```

# おわりに
今回は以下の流れで動作することを確認した。
1. ボタンを押す。 => func calculateButton
1. 計算する。 => calculatorBrain.calculateBMI
1. Segueを開始する。 => performSegue
1. Segueの該当するIDに対して、遷移先の情報を取得したり、値の設定をするなど、事前処理を実行する。 => func prepare(①〜④)


# 参考
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621413-performseguewithidentifier/

https://i-app-tec.com/ios/tap_gesture.html

https://capibara1969.com/1060/#toc5