Xcode8 Swift3でStoryboardを使用した画面遷移

## やること
SwiftでStoryboardを使った画面遷移を行う
とりあえず簡単な画面遷移ということで、画面遷移前に入力チェックをして、次の画面に値を受け渡し、画面遷移先で受け取った値を表示する

## 開発環境
Xcode 8
Swift 3

## プロジェクト構成
![image](https://qiita-image-store.s3.amazonaws.com/0/128475/0ff6de0c-247f-1ed7-682c-f429608aacf9.png)

今回編集したのは、以下の３ファイル

- Main.storyboard
- FirstViewController.swift
- SecondViewController.swift

## Storyboardの設定
![image](https://qiita-image-store.s3.amazonaws.com/0/128475/a1562df0-ab76-3e91-4a4d-090cac77dd3d.png)

UIViewControllerを２つ作成し、それぞれ後述する`FirstViewController`、`SecondViewController`と紐づける
`FirstViewController`には以下の3つのコントロールを配置

- 挨拶を選択する Picker View
- 挨拶をする人の名前を入力する Text Field
- 次の画面へ遷移する Button（後でSegueの設定するよ）

`SecondViewController`には以下の3つのコントロールを配置

- Navigation Bar
 - 前の画面に戻るための Bar Button Item（後でUnwind Segueの設定するよ）
- 挨拶を表示する Label

**画面遷移の設定**
`FirstViewController`の「挨拶する」ボタンを`control`キーを押しながら、`SecondViewController`にドラッグすると、画面の表示方法が選択できるので今回は`show`を選択
![image](https://qiita-image-store.s3.amazonaws.com/0/128475/af6bac31-1b1d-9a20-eaf5-021a37e70db3.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/128475/0369bfa4-d005-ca0a-11dc-7ab992643acb.png)

上記で作成したSegueのidentifierに名前をつける
![image](https://qiita-image-store.s3.amazonaws.com/0/128475/e62d308e-505b-c530-494c-baec57fcbabb.png)

## ソース
```swift:FirstViewController.swift
import Foundation
import UIKit

class FirstViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
    @IBOutlet weak var greetingType: UIPickerView!
    @IBOutlet weak var greetingTo: UITextField!
    
    let greetingTypes = ["おはよう", "こんにちは", "こんばんは"]
    var selectedGreetingType: String = ""
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    /// 画面遷移するかの判定処理
    override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool {
        if (identifier == "toSecondSegue") {
            if (self.greetingTo.text?.isEmpty)! {
                let alert = UIAlertController(title: "入力エラー", message: "名前を入力してください", preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "OK", style: .default))
                self.present(alert, animated: true, completion: nil)
                return false;
            }
        }
        return true;
    }
    
    /// 画面遷移時の処理
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "toSecondSegue") {
            let secondViewController:SecondViewController = segue.destination as! SecondViewController
            let selectedRow = self.greetingType.selectedRow(inComponent: 0)
            secondViewController.greetingType = self.greetingTypes[selectedRow]
            secondViewController.greetingTo = self.greetingTo.text!
        }
    }

    /// Storyboadでunwind sequeを引くために必要
    @IBAction func unwindToFirstView(segue: UIStoryboardSegue) {
    }
    
    /// 以下は挨拶選択を作成している
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }
    
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return greetingTypes.count
    }
    
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return greetingTypes[row]
    }
    
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        self.selectedGreetingType = greetingTypes[row]
    }
}
```

**画面遷移の判定**
`shouldPerformSegue(withIdentifier)`が画面遷移判定用のメソッドで、falseを戻すと画面遷移をキャンセルする
パラメータの`identifier`にStoryboardでSegueにつけた値がもらえるので、画面遷移先が複数ある場合は、この値で処理を分岐させる
今回は名前（Text Field）が入力されていない場合、アラートを出して画面遷移を中止する

**画面遷移処理**
`prepare(for segue)`が画面遷移時のメソッド
パラメータの`segue`が画面遷移先のオブジェクトとなっていて、先程と同じように`segue.identifier`で遷移先を判定するか、`segue.destination`が遷移先のViewControllerオブジェクトとなっているので、型で遷移先を判断することもできる
今回は`segue.identifier`で遷移先を特定し、`segue.destination`を遷移先の`SecondViewController`クラスにキャストして必要な値を受け渡す

**遷移先から戻る処理**
`unwindToFirstView`はStoryboardで戻る線を引くために必要となるメソッド
`@IBAction`をつけたメソッドでパラメータを`segue: UIStoryboardSegue`とする（メソッド名は自由につけられる）
閉じる処理などは特に記述する必要はないので、戻る際の処理が特に必要なければメソッドは空のままでよい
戻るボタンがある`SecondViewController`ではなく、戻り先の`FirstViewController`に作るのがポイント

メソッドを作成したらStoryboardを開き`SecondViewController`の「戻る」ボタンを`control`キーを押しながら上の３つのうち一番右の`Exit`アイコンにドラッグすると、上記で作成したメソッドが出てくるので選択する
![image](https://qiita-image-store.s3.amazonaws.com/0/128475/da9c7c92-daa8-cdc2-852c-21600cb37210.png)
![image](https://qiita-image-store.s3.amazonaws.com/0/128475/6322f4bd-8480-8388-9181-10fb6fd61808.png)

```swift:SecondViewController.swift
import Foundation
import UIKit

class SecondViewController: UIViewController {
    @IBOutlet weak var greetingLabel: UILabel!
    
    var greetingType: String = ""
    var greetingTo: String = ""

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.greetingLabel.text = String(format: "%@ %@さん", self.greetingType, self.greetingTo)
    }
}
```

**遷移先**
画面遷移時の値を受け取れるように`greetingType`,`greetingTo`の2つ変数を宣言しておき、`viewDidLoad`で受け取った値を表示

## 完成したもの
**画面起動時**
<img width="487" alt="スクリーンショット 2017-02-24 0.49.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/128475/22b3b7f9-d71f-83d9-9276-76ec0dbd0ceb.png">
**そのまま「挨拶」するボタンをタップ（入力エラー）**
<img width="487" alt="スクリーンショット 2017-02-24 0.49.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/128475/0fd65fea-c168-78e0-d824-f43f115ca42e.png">
**挨拶を撰択して、名前も入力**
<img width="487" alt="スクリーンショット 2017-02-24 0.49.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/128475/6709cb06-48ad-bd23-bb7a-476a0f8aad41.png">
**画面遷移**
<img width="487" alt="スクリーンショット 2017-02-24 0.49.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/128475/eeb2b7eb-4655-91c5-3faf-fb3680c1cc2d.png">