RxSwift + Action

## RxSwiftの派生ライブラリActionを使ってみる
RxSwiftの派生プロジェクトにActionというライブラリがあります。
RxSwiftでの動作の定義を入出力をはっきりとさせて管理するものっぽい。
Actionの構成要素は次の通り。

|種類|概要|
|---|---|
|Action<Input, Element>  |動作定義 |
|Input  |入力要素  |
|Element  |出力要素  |
|Errors |エラー情報 |

この４つで管理するフォーマットが組める！　というのが売りみたいです

### よくあるログインの動作を例に
こんなのを作って確かめてください

```ViewController.swift
import UIKit
import RxSwift
import RxCocoa
import Action
import NSObject_Rx

class ViewController: UIViewController {
    @IBOutlet weak var usernameTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var loginButton: UIButton!
```

### Actionの定義
第一引数をinput、第二引数をonNextで渡す変数として定義

```swift
    // ユーザーアカウントとパスワードでログイン
    let loginAction: Action<(String,String), Bool> = Action {
            (username, password) in
            return Observable.just(true) // 実際のアプリでこういうのはないですね　APIに投げてリクエスト処理などが入ると思います
    }
```

### Action実行前の処理を定義
Actionがコールされる直前の処理を定義　このときにinputに値が渡るようにする

```swift
   // よくあるユーザーアカウントとパスワードのObservable化
   let usernameAndPassword = Observable.combineLatest(usernameTextField.rx.text.orEmpty, 
                          passwordTextField.rx.text.orEmpty)
 
    // ログインボタンがタップされた時に上の値をactionのinputにbind
　　loginButton.rx.tap.asObservable()
            .withLatestFrom(usernameAndPassword)
            .bind(to: loginAction.inputs)
            .disposed(by: rx.disposeBag)
```
loginActionの第一引数が(String,String)にユーザーアカウントとパスワードが渡るようにする
変数とinputをbindするものと考えていいっぽい

### 実行後
inputに値が入った直後にActionが実行される
Actionが実行された後は、実行結果がelementに入る　 こういうので確かめられる

```swift
        loginAction.elements
            .filter{ $0 }
            .subscribe( onNext:{
                          print($0)
                          print("login ok!")
                        }
            )
            .disposed(by: rx.disposeBag)
```

エラーが起きた時は errorsを参照

```swift
        loginAction.errors
            .subscribe(
                onError:{ error in
                            print(error.localizedDescription)
                }
            )
            .disposed(by: rx.disposeBag)
```

### 補足
Action以外の要素は、入力 / 結果 / エラー を表します。つまりこれらの変数をうまく利用することで、
 start / end /error のトリガー処理も一定のフォーマットで記述することができます。
上のログインの例で考えるとこういう例も考えられます。

```swift
       let startTrigger = PublishSubject<Void>() // 前もってSubjectを定義しておく
       
       loginbutton.rx.tap.asDriver()  // ボタンタップでSubjectをキック
            .drive(self.startTrigger)
            .disposed(by: disposeBag)

       // ログイン処理が走る
       startTrigger.asObservable()
       .withLatestFrom(usernameAndPassword)
            .bind(to: loginAction.inputs)
            .disposed(by: rx.disposeBag)
```

ログイン後ではelementを監視して次の処理を定義

```swift
       let successTrigger: Observable<Bool> // 前もって定義しておく
       
       // loginActionが成功時にonNextに渡すBool値とbind
       self.successTrigger = loginAction.elements
       // ログイン成功
        self.sucessTrigger.asObservable()
            .subscribe(onNext: { [weak self] _ in
                // ログイン後の画面へ遷移など
                
            })
            .disposed(by: disposeBag)
```

エラー処理はこうすれば楽かも？

```swift
        loginAction.error.asDriver()
            .drive(onNext: { [weak self] error in
                let alert = UIAlertController(title: "エラー", message: error.localizedDescription, preferredStyle: .alert)
                alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
                self?.present(alert, animated: true, completion: nil)
            })
            .disposed(by: disposeBag)
```

### Actionの明示的な実行
動作確認などのためにActionを実行したい場合はexcuteメソッドでinputに相当する値を渡す

```swift
        loginAction.execute(("user","pass"))
            .subscribe{
                print("loginAction.execute")
                print($0)
            }
            .disposed(by: rx.disposeBag)
```

### いくつかサンプルを作成してみました。
- <a href="https://github.com/katafuchix/RxLoginSample">ログインフォーム 入力チェックサンプル</a>
- <a href="https://github.com/katafuchix/YahooImageSearchAction">Yahoo 画像検索</a>
- <a href="https://github.com/katafuchix/DmmItemSearchAction">DMM商品検索</a>