Delegateを使ったStoryboard要らずの画面遷移 Swift

今回はインターンの復習も兼ねて、簡単なアプリを作成しました。
題して、Delegateを使ったStoryboard要らずの画面遷移。

仕組みはとてもシンプルでボタンが押されたとき画面遷移する。画面遷移したページにあるボタンを押すと元のページに戻るというものです。
インターンを初めて１、２ヶ月目の頃大苦戦した記憶があります。
とりあえず大まかなやったことを書きます。

## Storyboardの消去
まずは当然Storyboardの消去から。
参考にしたのはこのページです。
https://qiita.com/rika-tawashi/items/d975c2d9f85e8bb4aef5

手順は以下の4つ。

- プロジェクト作成
- 「Main.storyboard」を削除
- 「Info.plist」の「Main storyboard file base name」を「Main」→なし
- 「AppDelegate.swift」にビューを定義する

AppDelegate.swiftで以下のコードを入力します。

```swift
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = FirstViewController()
window?.makeKeyAndVisible()
return true
```

これによりFirstViewControllerが呼ばれます。

## AutoLayoutの設定
次にAutoLayoutです。

```swift
let nextButton = UIButton()
view.addSubview(nextButton)
nextButton.translatesAutoresizingMaskIntoConstraints = false
nextButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
nextButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
nextButton.heightAnchor.constraint(equalToConstant: 150.0).isActive = true
nextButton.widthAnchor.constraint(equalToConstant: 200.0).isActive = true
```
- addSubviewとはビューを追加するというものと自分は考えています。
なのでview.addSubview(nextButton)となります。

- AutoresizingMaskをAuto Layoutに変換しないよう、translatesAutoresizingMaskIntoConstraintsをfalseにします。

- NSLayoutAnchorを使って制約をします。centerXAnchorは水平方向の制約、centerXAnchorは垂直方向の制約です。

##呼び出し
- ボタンが押されたとき関数nextButtonTappedが呼ばれます。それによりプライベート関数のshowNextViewControllerが呼ばれます。

- showNextViewControllerでNextViewControllerのdelegateを自分にセットします。

- modalTransitionStyleはモーダルの画面の切り替わり方を設定するものです。
参考にしたのはこのページです。
https://qiita.com/osamu1203/items/6c203f3f048f9d7540f3

これより画面遷移されてNextViewControllerが呼ばれます。

```swift
    @objc func nextButtonTapped(_ sender: UIButton) {
        showNextViewController()
    }

    private func showNextViewController() {
        let nextVC = NextViewController()
        nextVC.delegate = self
        nextVC.modalTransitionStyle = UIModalTransitionStyle.flipHorizontal
        present(nextVC, animated: true, completion: nil)
    }
```

## プロトコルの定義
- NextViewControllerにdelegateのためのプロトコル定義します。
- FirstViewControllerDelegateでdelegateを定義します。
- backButtonが押されたとき呼ばれます。

https://qiita.com/KunioTerada/items/79b30163e4d16cd4e3f7

```swift
protocol FirstViewControllerDelegate: class {
    func nextViewController(_ nextViewController: NextViewController, backButton button: UIButton)
}
```

## extension
最後にextensionでクラスを拡張します。これによってNextViewControllerでbackButtonが押されたとき先ほどのdelegateが呼ばれて、画面遷移が起こり画面が戻ってきます。

```swift
extension FirstViewController: FirstViewControllerDelegate {
    func nextViewController(_ nextViewController: NextViewController, backButton button: UIButton) {
        dismiss(animated: true, completion: nil)
    }
}
```

## 最後に
今後もちょっとずつ成果物をQiita等に上げていきたいなと思います！
おかしなところ、無駄なところがあればご指摘お願いします！
以下完成したコードになります。

```swift
import UIKit

class FirstViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = UIColor.white

        let nextButton = UIButton()

        nextButton.setTitle("Tap!", for: .normal)
        nextButton.backgroundColor = UIColor.orange
        nextButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 30.0)
        nextButton.setTitleColor(UIColor.white, for: UIControl.State.normal)
        nextButton.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside)
        view.backgroundColor = UIColor.white
        view.addSubview(nextButton)
        nextButton.translatesAutoresizingMaskIntoConstraints = false
        nextButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        nextButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        nextButton.heightAnchor.constraint(equalToConstant: 150.0).isActive = true
        nextButton.widthAnchor.constraint(equalToConstant: 200.0).isActive = true
    }

    @objc func nextButtonTapped(_ sender: UIButton) {
        showNextViewController()
    }

    private func showNextViewController() {
        let nextVC = NextViewController()
        nextVC.delegate = self
        nextVC.modalTransitionStyle = UIModalTransitionStyle.flipHorizontal
        present(nextVC, animated: true, completion: nil)
    }
}

extension FirstViewController: FirstViewControllerDelegate {
    func nextViewController(_ nextViewController: NextViewController, backButton button: UIButton) {
        dismiss(animated: true, completion: nil)
    }
}
```
```swift
import UIKit

protocol FirstViewControllerDelegate: class {
    func nextViewController(_ nextViewController: NextViewController, backButton button: UIButton)
}

class NextViewController: UIViewController {
    
    weak var delegate: FirstViewControllerDelegate?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.orange
        
        let backButton = UIButton()

        backButton.setTitle("BACK", for: .normal)
        backButton.titleLabel?.font = UIFont.boldSystemFont(ofSize: 30.0)
        backButton.setTitleColor(UIColor.orange, for: UIControl.State.normal)
        backButton.backgroundColor = UIColor.white
        backButton.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)
        view.backgroundColor = UIColor.orange
        view.addSubview(backButton)
        backButton.translatesAutoresizingMaskIntoConstraints = false
        backButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        backButton.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        backButton.heightAnchor.constraint(equalToConstant: 150.0).isActive = true
        backButton.widthAnchor.constraint(equalToConstant: 200.0).isActive = true
    }
    
    @objc func backButtonTapped(_ sender: UIButton) {
        delegate?.nextViewController(self, backButton: sender)
    }
}
```

```swift
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = FirstViewController()
        window?.makeKeyAndVisible()
        return true
    }
}
```
<img width="408" alt="スクリーンショット 2019-02-13 20.38.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/311344/3e20c4b3-6e5c-565b-5eec-76a75377c437.png">
<img width="405" alt="スクリーンショット 2019-02-13 20.38.35.png" src="https://qiita-image-store.s3.amazonaws.com/0/311344/5938339c-10ff-cabd-6492-5052712746fa.png">