ActionSheet, UIImagePickerのRxSwift実装

##RxSwiftのExampleからのコピー
3ファイルをコピーしておきます。
- RxImagePickerDelegateProxy.swift
- UIImagePickerController+Rx.swift
- UIImagePickerController+RxCreate.swift

##AppDelegateへの記述追加
上記３ファイルを利用する場合には忘れないように。

```swift
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        // for ImagePicker この１行を追加
        RxImagePickerDelegateProxy.register { RxImagePickerDelegateProxy(imagePicker: $0) }

        return true
    }
```

##アクションシートのObsrvable化
よくあるあれ

```swift
import UIKit
import RxSwift
import RxCocoa

// アクションシートの項目を指定する構造体
struct ActionSheetItem<Type> {
    let title: String
    let selectType: Type
    let style: UIAlertActionStyle
}

extension UIAlertController {
    // アクションシートに項目を追加し、Observable化
    func addAction<T>(actions: [ActionSheetItem<T>], cancelMessage: String, cancelAction: ((UIAlertAction) -> Void)?) -> Observable<T> {
        return Observable.create { [weak self] observer in
            actions.map { action in
                return UIAlertAction(title: action.title, style: action.style) { _ in
                        observer.onNext(action.selectType)
                        observer.onCompleted()
                    }
                }.forEach { action in
                    self?.addAction(action)
                }

            self?.addAction(UIAlertAction(title: cancelMessage, style: .cancel) {
                cancelAction?($0)
                observer.onCompleted()
            })

            return Disposables.create {
                self?.dismiss(animated: true, completion: nil)
            }
        }
    }
}
```
選択項目に色々使えるようにジェネリック型で宣言しておきます。

## UIViewControllerからアクションシートを呼ぶ
上記で作成したアクションシートをUIViewControllerから呼べるようにします。

```swift
import UIKit
import RxSwift
import RxCocoa

extension UIViewController {
    // Observable化したアクションシートの表示
    func showActionSheet<T>(title: String?, message: String?, cancelMessage: String = "キャンセル", actions: [ActionSheetItem<T>]) -> Observable<T> {
        let actionSheet = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)

        return actionSheet.addAction(actions: actions, cancelMessage: cancelMessage, cancelAction: nil)
            .do(onSubscribed: { [weak self] in
                self?.present(actionSheet, animated: true, completion: nil)
            })
    }
}
```
アクションシートの選択項目を追加した後に、presentを実行して表示します。
当然ですが、項目を選択した後に、selectTypeの内容が.nextで渡されるようにします。

## ViewModel作成
RxSwiftのサンプルをちょっと真似してみます。Wireframeを利用します。

```swift
import Foundation
import RxSwift
import RxCocoa

class SampleViewModel  {

    // Inputs
    typealias Inputs = (
        Signal<Void>
    )

    typealias Wireframe  = (
        SampleWireframeType
    )

    // Outputs
    let selectedImage: BehaviorRelay<UIImage?>

    private let disposeBag = DisposeBag()

    init(inputs: Inputs, wireframe: Wireframe) {

        self.selectedImage = wireframe.selectedImage
        
        // アクションシート表示
        inputs.emit(onNext: { _ in
            // アクションシート選択項目
            var actions = [ActionSheetItem<UIImagePickerControllerSourceType>(
                                title: "ライブラリから選択",
                                selectType: UIImagePickerControllerSourceType.photoLibrary,
                                style: .default)]

            if UIImagePickerController.isSourceTypeAvailable(.camera) {
                actions.insert(ActionSheetItem<UIImagePickerControllerSourceType>(
                                    title: "カメラを起動",
                                    selectType: UIImagePickerControllerSourceType.camera,
                                    style: .default), at: 0)
            }
            wireframe.shwoActionSheet(title: "画像設定", message: "選択してください。", actions: actions)
        })
        .disposed(by: self.disposeBag)
    }
}

```
ボタンを押したときに、UIImagePickerControllerSourceTypeごとに選択項目を持ったアクションシートを表示します。selectTypeに利用するUIImagePickerControllerSourceTypeを指定します。

## Wireframe作成
RxSwiftサンプルを参考に、、、

```swift
import UIKit
import RxSwift
import RxCocoa

protocol SampleWireframeType {
    func shwoActionSheet<T>(title: String, message: String, actions: [ActionSheetItem<T>])
    var selectedImage: BehaviorRelay<UIImage?> { get }
}


class SampleWireframe: SampleWireframeType {

    var viewController: UIViewController? { return sampleViewController }
    private weak var sampleViewController: SampleViewController?

    private let disposeBag = DisposeBag()

    let selectedImage: BehaviorRelay<UIImage?>

    init(view: SampleViewController) {
        self.sampleViewController = view
        self.selectedImage = BehaviorRelay<UIImage?>(value: nil)
    }

    // アクションシートを起動してUIImagePickerController起動
    func shwoActionSheet<T>(title: String, message: String, actions: [ActionSheetItem<T>]) {
        viewController?.showActionSheet(title: title, message: message, actions: actions)
            .subscribe({ [unowned self] event in
                if let sourceType = event.element as? UIImagePickerController.SourceType {
                    switch sourceType {
                    case .camera:
                        self.launchPhotoPicker(.camera)
                    case .photoLibrary:
                        self.launchPhotoPicker(.photoLibrary)
                    case .savedPhotosAlbum:
                        break
                    }
                }
            })
            .disposed(by: self.disposeBag)
    }

    // UIImagePickerControllerの起動と選択した画像の処理
    private func launchPhotoPicker(_ type: UIImagePickerController.SourceType) {
        UIImagePickerController.rx.createWithParent(self.viewController) { picker in
            picker.sourceType = type
            picker.allowsEditing = true
        }
        .flatMap { $0.rx.didFinishPickingMediaWithInfo }
        .take(1)
        .map { info in return info[UIImagePickerControllerOriginalImage] as? UIImage }
        .bind(to: self.selectedImage)
        .disposed(by: self.disposeBag)
    }
}
```
アクションシートの項目を選択した後に、subscribeで選択したselectTypeが得られます。そのままUIImagePickerControllerを起動して選択した画像の処理も行います。
switchなくてもいいけど、、、ここで分岐できるという目印のために、、、


## ViewControllerの作成
作ったものを利用する例。

```swift
import UIKit
import RxSwift
import RxCocoa

class SampleViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var button: UIButton!

    private var viewModel: SampleViewModel!
    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        // ViewModel初期化
        viewModel = SampleViewModel(
                inputs: button.rx.tap.asSignal(),
                wireframe: SampleWireframe(view: self)
            )

        // 画像選択
        viewModel.selectedImage
            .asObservable()
            .bind(to: self.imageView.rx.image)
            .disposed(by: self.disposeBag)

    }
}
```

[サンプル](https://github.com/katafuchix/ActionSheet-ImagePickerSample)