UIImagePickerController表示中にsourceTypeを切り替える

# TL;DR

表示中の`UIImagePickerController`の`sourceType`変更はうまく動かない
→ カメラ起動、フォトライブラリ起動でボタンを分けて先に`sourceType`決めさせる
→ またはインスタンス再生成する


# やりたいこと

カメラを起動して撮影した画像を取得したい。
また、オプションとしてフォトライブラリ内からも画像を選択できるようにしたい。

# やったこと

## 実装方針
`UIImagePickerController`でカメラを起動
フォトライブラリボタンがタップされたら`UIImagePickerController`の`sourceType`を`camera`から`photoLibrary`に変更する

## ソース

本来は`UIImagePickerController`の`cameraOverlayView`を使用して
カメラ表示中にフォトライブラリボタンを設ける予定だが、
とりあえずテストのため`picker`のキャンセルボタンで`sourceType`切り替えを実装

```Swift:FirstViewController.swift
import UIKit
import Photos

class FirstViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
    
    var picker: UIImagePickerController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 許可リクエスト
        AVCaptureDevice.requestAccess(for: AVMediaType.video) { (Bool) in
            return
        }
    }
    
    /// Picker起動ボタン
    ///
    /// - Parameter sender:
    @IBAction func btn1_TouchUpInside(_ sender: Any) {
        pickerInit(type: UIImagePickerController.SourceType.camera)
    }
    
    /// Picker初期化
    ///
    /// - Parameter type: sourceType
    func pickerInit(type: UIImagePickerController.SourceType){
        self.picker = UIImagePickerController()
        self.picker.sourceType = type
        self.picker.delegate = self
        
        self.picker.navigationBar.tintColor = UIColor.white
        self.picker.navigationBar.barTintColor = UIColor.gray
        
        present(self.picker, animated: false, completion: nil)
    }

    // MARK: - UIImagePickerControllerのデリゲートメソッド
    
    /// 画像選択時
    ///
    /// - Parameters:
    ///   - picker:
    ///   - info:
    private func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        // モーダルビューを閉じる
        self.picker.dismiss(animated: true, completion: nil)
    }
    
    /// キャンセル時
    ///
    /// - Parameter picker:
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        // 表示中のpickerのsourceTypeを切り替えるだけ
        if picker.sourceType == UIImagePickerController.SourceType.photoLibrary {
            self.picker.sourceType = UIImagePickerController.SourceType.camera
        }
        else {
           self.picker.sourceType = UIImagePickerController.SourceType.photoLibrary
        }
    }
}
```

## 結果

### スクショ

1.起動時
<img width="200" alt="起動時.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/275964/f1240665-0786-3e90-5c8e-986f3ee7e93f.png">

2.Picker起動(カメラ)
<img width="200" alt="カメラ.png" src="https://qiita-image-store.s3.amazonaws.com/0/275964/ee786f69-2247-142e-75e4-e9369b1baf4a.png">

3.sourceType切り替え(フォトライブラリ)
<img width="200" alt="フォトライブラリ.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/275964/731b588f-7290-dcd6-2da4-802c2a77823d.png">

4.sourceType切り替え(カメラ)
<img width="200" alt="カメラ.png" src="https://qiita-image-store.s3.amazonaws.com/0/275964/ee786f69-2247-142e-75e4-e9369b1baf4a.png">

5.sourceType切り替え(フォトライブラリ)
<img width="200" alt="フォトライブラリ？.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/275964/7ee78d0b-b683-d597-abe1-2c847bf155b6.png">

！！！？！？！！？？？！！？！？？！？！？？？ｗｗｗｗｗｗｗｗｗ
カメラは普通なのにフォトライブラリ2回目表示すると何も出ない！なんやこれ！！

### 調査

レイアウト見てみるか…(最近覚えた)

1.正常時

<img width="902" alt="スクリーンショット 2018-10-12 12.51.44.png" src="https://qiita-image-store.s3.amazonaws.com/0/275964/8b1aaceb-c327-eb22-5b89-0196eb4ad175.png">

2.異常時

<img width="906" alt="スクリーンショット 2018-10-12 12.52.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/275964/2e7a1809-b5d7-4b4b-4424-95ce91559021.png">

`PUPhotoPickerHostViewController`が消えた…！？
ていうか誰？誰なの？怖いよぉ！

ググっても出てこないし結局見てもよくわかりませんでした。

# じゃあどうするか

一回作った`UIImagePickerController`でコロコロ`sourceType`変えてるのがまずいと予想。
写真撮影とフォトライブラリからの選択はボタン分けてるアプリばっかりだし。

## 実装方針

`UIImagePickerController`でカメラを起動
フォトライブラリボタンがタップされたら表示中の`UIImagePickerController`の`sourceType`変更ではなく、`sourceType`を変更した`UIImagePickerController`インスタンスを新規で生成する。

## ソース

本来はカメラ表示中にフォトライブラリボタンを設ける予定だが以下略

```Swift:SecondViewController.swift
import UIKit
import Photos

class SecondViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate{

    var picker: UIImagePickerController!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 許可リクエスト
        AVCaptureDevice.requestAccess(for: AVMediaType.video) { (Bool) in
            return
        }
    }

    /// Picker起動ボタン
    ///
    /// - Parameter sender:
    @IBAction func btn1_TouchUpInside(_ sender: Any) {
        pickerInit(type: UIImagePickerController.SourceType.camera)
    }
    
    /// Picker初期化
    ///
    /// - Parameter type: sourceType
    func pickerInit(type: UIImagePickerController.SourceType){
        self.picker = UIImagePickerController()
        self.picker.sourceType = type
        self.picker.delegate = self
        
        self.picker.navigationBar.tintColor = UIColor.white
        self.picker.navigationBar.barTintColor = UIColor.gray
        
        present(self.picker, animated: false, completion: nil)
    }
    
    // MARK: - UIImagePickerControllerのデリゲートメソッド
    
    /// 画像選択時
    ///
    /// - Parameters:
    ///   - picker:
    ///   - info:
    private func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
        
        // モーダルビューを閉じる
        self.picker.dismiss(animated: true, completion: nil)
    }
    
    /// キャンセル時
    ///
    /// - Parameter picker:
    func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
        // 一旦表示中のモーダルを閉じる
        self.picker.dismiss(animated: false, completion: nil)
        
        // sourceTypeを切り替えて再度インスタンス生成から行う
        if picker.sourceType == UIImagePickerController.SourceType.photoLibrary {
            pickerInit(type: UIImagePickerController.SourceType.camera)
        }
        else {
            pickerInit(type: UIImagePickerController.SourceType.photoLibrary)
        }
    }
}

```

## 結果

何度切り替えを行なっても正常にカメラ、フォトライブラリが表示されるようになりました。

# まとめ

ぶっちゃけ要因はよくわかりませんでした。
表示中の`UIImagePickerController`の`sourceType`変更はガイドラインに沿ってないのかなぁ…？
一旦このやり方で解決はしたけど、もっと楽な方法とかありそう。