RxSwiftのすぐに取り込める使用例をまとめてみた🏄🏻

#自分自身の理解を確認するためにRxSwiftのサンプルアプリを作ってみた。
**サンプルコードは[ここ](https://github.com/Ryochan/RxOperator)**
この記事の大部分はRxのオペレーターやメソッドの説明になっています！(基礎的な部分が多め、自分もそこまで書けないので😅)でもこの記事をみて、是非最後に紹介する簡単なフォームバリデーションとボタンの制御から自分のプロジェクトに取り込んでみてください。
まだまだ少ないですが、これからどんどん更新していきます！

*他にもこんなサンプルはどう？とかありましたらコメントお願いします*

##Sample 0 (MenuTableViewController)
[View ALL](https://github.com/Ryochan/RxOperator/blob/master/RxOperators/MenuTableViewController.swift)

サンプル一覧を表示する`tableView`をRxで実装してみました！


```swift:MenuTableViewController
let operators: Driver<[Operator]> = Driver.just([
               Operator(title: "", description: ""),
               ....
            ])
        
        operators.asDriver()
            .drive(tableView.rx_itemsWithCellIdentifier("TitleCell")) { _, rxOperator, cell in
                cell.textLabel?.text = rxOperator.title
            }
            .addDisposableTo(disposeBag)
        
        tableView.rx_itemSelected
            .withLatestFrom(operators) { indexPath, operators in
                return (operators[indexPath.row], indexPath)
            }
            .subscribeNext { [weak self] (rxOperator, indexPath) in
                let storyboard = UIStoryboard(name: "Main", bundle: nil)
                switch indexPath.row {
                case 0:
                    .....
                default:
                    break
                }
            }
            .addDisposableTo(disposeBag)
```

Driverについては[この記事](http://qiita.com/yuzushioh/items/0a4483502c5c8569790a)を確認してください。

ここでは`cell`のタップされた`indexPath`が流れるストリームと`operators`ストリームを`withLatestFrom`というオペレーターを使ってがっちゃんこして、その`indexPath`に該当する`Operator`と`indexPath`をリターンしています！

・`withLatestFrom`は`combineLatest`と同じような働きをします。

<img width="812" alt="Screen Shot 2016-04-23 at 4.20.20 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/80383/20ac2e2f-6d56-5352-9de0-6c8a3763985a.png">

単に他のストリームをくっつけたいだけなら以下のように書くだけでも大丈夫です。

```swift:Sample
   .....
   .withLatestFrom(ストリーム)
   ...subscribe...
```

##Sample 1

ボタンがタップされた時に`String`のストリームをくっつけ、それをtextViewに`bindTo`(`Drive`)するサンプルです。

```swift:Sample1ViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let description = Driver<String>
            .just(rxOperator.description)
        
        rxButton.rx_tap.asDriver()
            .flatMap { _ in
                return description
            }
            .drive(descriptionTextView.rx_text)
            .addDisposableTo(disposeBag)
    }
```

・`flatMap`は二つのストリームを一つのストリームに変化させます。
↓こんな感じ
<img width="780" alt="Screen Shot 2016-04-23 at 4.27.03 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/80383/e08882e3-8105-248f-5191-81ae10166e4d.png">

サンプルコードでは`UIButton`の`rx_tap`を使ってタップごとに`Void`が流れるストリームを作ります。そして`Void`が流れてきたら`flatMap`で`description`という`String`のストリームをつなげています！

画像でみると ○--- >の方が`Void`のストリームにあたり、□---|->の方が`String`のストリームにあたります。

・`just`は特定のタイプのobservableを一つ排出するストリームを作ります。
<img width="842" alt="Screen Shot 2016-04-23 at 5.34.19 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/80383/3fa162ed-2294-a8c5-5e19-d60c90f74441.png">

##Sample 2

5秒ごとにenumで定義されている`operators`をランダムにラベルに表示するサンプルです。

```swift:Sample1ViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()
        
        enum operators: UInt32 {
            case rx_sentMessage
            case map
            case interval
            case of
            case merge
        }
        
        let firstTrigger = Driver
            .just(())
        
        let intervalTrigger = Driver<Int>
            .interval(5.0)
            .map { _ in }
        
        let mergedTrigger = Driver
            .of(
                firstTrigger,
                intervalTrigger
            )
            .merge()
        
        let operatorName = mergedTrigger.asDriver()
            .map { _ in String(operators(rawValue: arc4random_uniform(5))!) }
        
        operatorName
            .drive(operatorLabel.rx_text)
            .addDisposableTo(disposeBag)
        
        Driver
            .just(rxOperator.description)
            .drive(descriptionTextView.rx_text)
            .addDisposableTo(disposeBag)
    }
```

・`map`はストリームから排出されたアイテム一つ一つになんらかしらの関数を適用させて形を変えます！(説明すごく下手)
サンプルないでは`map { _ in }`で全てのアイテムを`Void`に変形させて返していて、下の図では各アイテムを×10しています。

<img width="802" alt="Screen Shot 2016-04-23 at 9.46.41 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/80383/9515459f-6a2f-b489-a3a4-09b561a3b019.png">


・`interval`は指定されたタイムスパンで０から順番に`Int`を排出するストリームを作ります
<img width="815" alt="Screen Shot 2016-04-23 at 5.37.00 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/80383/9ddec65a-adf5-47f4-8fcd-596f534e1e06.png">

このサンプルでは`map { _ in }`を使って`Int`から`Void`を返すようにしているので、毎５秒ごとに`Void`を排出しています。


・`merge()`は複数のストリームを時系列に合わせて合体させます。

このサンプルの場合は`firstTrigger`と`intervalTrigger`を合わせて`mergedTrigger`にしています！
これを使えば複数のボタンを一度に制御したりできるようになります。

<img width="825" alt="Screen Shot 2016-04-23 at 9.17.40 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/80383/8a97c576-cd04-151f-6c72-21ed61d2871f.png">

##Sample 3

`concat`を使って`viewWillAppear`のタイミングで次のストリームを合体させて、"concat発動"を`map`で返してtextLabelに`Drive`しています！(Sampleとしてなりたっていないのですが`concat`とかについて説明させてください。。。)

```swift:Sample3ViewController.swift
rx_sentMessage(#selector(UIViewController.viewWillAppear(_:)))
            .map { _ in }
            .bindTo(viewWillAppearTrigger)
            .addDisposableTo(disposeBag)
        
        let printText = Observable
            .just(())
        
        //ここもUIに関するところなので本来はDriverの方が向いている。が、Observable版もサンプルとして残しておきます。
        Observable
            .of(
                Observable.never().takeUntil(viewWillAppearTrigger),
                printText
            )
            .concat()
            .map { _ in "concat発動" }
            .doOnNext { text in
                print(text)
            }
            .bindTo(textLabel.rx_text)
            .addDisposableTo(disposeBag)
        
        Driver
            .just(rxOperator.description)
            .drive(descriptionTextView.rx_text)
            .addDisposableTo(disposeBag)

```

・ `concat`は一つ目のストリームが`onCompleted`すると２つ目のストリームを一つ目の前に合体させます！

<img width="789" alt="Screen Shot 2016-04-23 at 9.35.38 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/80383/b1501962-7e71-dc04-a0e0-6195fbbb084d.png">

このサンプルでは`Observable.never().takeUntil(ストリーム)`を使って`never()`という何も流れてこないストリームを`takeUntil()`を使って`onCompleted`しています！

↓`takeUntil()` 指定したストリームに最初のObservableアイテムが流れてきた時に、そのストリームを`onCompleted`にする！
下の例だと`0`が来たタイミングで上のストリームが終了している。

<img width="799" alt="Screen Shot 2016-04-23 at 9.42.51 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/80383/ab9246da-8fa4-621c-d6dc-9286a939885b.png">



##Sample 4

最後に今までにでてきたオペレーターを駆使して、簡単なフォームバリデーションを実装してみました！多分RxSwiftのサンプルでは一番基礎的！

```swift:Sample4ViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let description = Driver
            .just(rxOperator.description)
        
        let usernameValidation = usernameTextField.rx_text.asDriver()
            .map { [weak self] username -> Bool in
                return username.characters.count > self?.minWordCount
            }
        
        let passwordValidation = passwordTextField.rx_text.asDriver()
            .map { [weak self] password -> Bool in
                return password.characters.count > self?.minWordCount
            }
        
        usernameValidation
            .drive(usernameValidationLabel.rx_hidden)
            .addDisposableTo(disposeBag)
        
        passwordValidation
            .drive(passwordValidationLabel.rx_hidden)
            .addDisposableTo(disposeBag)
        
        let signUpButtonEnabled = [usernameValidation, passwordValidation]
            .combineLatest { !$0.contains(false) }
        
        signUpButtonEnabled
            .drive(signUpButton.rx_enabled)
            .addDisposableTo(disposeBag)
        
        signUpButtonEnabled
            .driveNext { [weak self] valid in
                self?.signUpButton.backgroundColor = valid ?
                    UIColor(red: 135/255, green: 132/255, blue: 200/255, alpha: 1) : UIColor(red: 135/255, green: 132/255, blue: 200/255, alpha: 0.5)
            }
            .addDisposableTo(disposeBag)
        
        signUpButton.rx_tap.asDriver()
            .flatMap { _ in
                return description
            }
            .drive(descriptionTextView.rx_text)
            .addDisposableTo(disposeBag)
    }
```

簡単に解説すると↓

```swift:wordCountValidation
let usernameValidation = usernameTextField.rx_text.asDriver()
            .map { [weak self] username -> Bool in
                return username.characters.count > self?.minWordCount
            }

let passwordValidation = passwordTextField.rx_text.asDriver()
            .map { [weak self] password -> Bool in
                return password.characters.count > self?.minWordCount
            }
```

上記のコードでユーザーネームとパスワードテキストに入っている文字数が最低文字数を超えているかをまず判断します。
なのでこの二つの`usernameValidation`と`passwordValidation`は`Bool`になります。

そして次にこの二つの値を使って、「文字数を超えていません！」ラベルを`rx_hidden`を使って制御します！
今回はUIの部分なので`Drive`を使ってバインドしています！
↓この部分

```swift:rx_hidden
usernameValidation
            .drive(usernameValidationLabel.rx_hidden)
            .addDisposableTo(disposeBag)

passwordValidation
            .drive(passwordValidationLabel.rx_hidden)
            .addDisposableTo(disposeBag)
```

次にボタンの制御です。

```swift:rx_enabled
let signUpButtonEnabled = [usernameValidation, passwordValidation]
            .combineLatest { !$0.contains(false) }

signUpButtonEnabled
            .drive(signUpButton.rx_enabled)
            .addDisposableTo(disposeBag)
```

次に`combineLatest`を使って`usernameValidation`と`passwordValidation`を合体させます！そしてその結果を
`rx_enabled`にバインドして、textFieldが両方埋まった状態ではないとボタンをおせなくしてあります！

最後にボタンをタップした処理をかいて簡単なフォームバリデーションの完成です！


なにか「ーーーのサンプルがみてみたい！」みたいな意見があったら是非お願いしますm(_ _)m
是非この機会にReactive Programmingを自身のプロジェクトにいれてみてください！！