よく使いそうなRxSwiftのオペレーターの勉強をしてみた（flatMap, flatMapFirst, flatMapLatest 等）

[Atrae Advent Calendar 2019](https://qiita.com/advent-calendar/2019/atrae)　の１０日目を担当するアガツマです。
普段は、ビジネス版マッチングアプリ [yenta](https://yenta.talentbase.io/yenta) のiOS版を開発をしています。

私は今、RxSwiftの勉強をしています。
その中で、基礎となる一部のオペレーターの動作についてまとめてみました。
（まだ学習中で、理解が深くない部分もあるので間違っていたらコメントお願います！）

RxSwiftの**オペレーター**とは、Observableに用意されているイベントを加工する用のメソッドのことを指します

勉強をすすめる上で
[オブザーバーパターンから始めるRxSwift入門](https://qiita.com/k5n/items/17f845a75cce6b737d1e)
という記事がとても参考になったのでRxSwiftについて知りたい方はこちらも読んでみるのをオススメします。
(この記事では、マーブルダイアグラムをいきなり書いてしまっていますがこの記事に詳しい解説が載っています)

# 一般的なオペレーター（一部抜粋）
## filter

**処理**
ある条件に合致するイベントだけ通知する。

**用途**
通知するイベントに条件をつけたい場合
（○文字以下だったら通知しない、イベントがtrueになった場合のみ通知したい）

**コード**

```swift:
let observable = Observable.of(1, 10, 2, 9, 3, 8, 4, 7, 5, 6)
            .filter { $0 < 5 }
            .subscribe(onNext: {
                print("onNext: ", $0)
            })
```

**出力結果**

```
onNext:  1
onNext:  2
onNext:  3
onNext:  4
```

**マーブルダイアグラム**
<img width="790" alt="スクリーンショット 2019-12-10 21.47.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266462/6b1fd3b6-38ec-5727-3aee-f6cbdf9f1a54.png">



## skip

**処理**
先頭から指定した数だけイベントを無視してスキップする。

**用途**
skip(1)を利用することで、最初の値を無視して、変化だけを検知するような場合に利用

**コード**

```swift:
let observable = Observable.of(1, 2, 3, 4, 5)
            .skip(1)
            .subscribe(onNext: {
                print("onNext: ", $0)
            })
```
**出力結果**

```
onNext:  2
onNext:  3
onNext:  4
onNext:  5
```

**マーブルダイアグラム**
<img width="792" alt="スクリーンショット 2019-12-10 21.50.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266462/63c2a6fe-3c6c-52bb-c357-a06550e171c9.png">


##map

**処理**
1つのObservableのイベントの要素を別の値に変換する。

**用途**
すべてのイベントに対して処理を適応したい場合
（すべての値を10倍したい、入力されてきた文字列をすべて小(大)文字で扱いたい）

**コード**

```swift:
let observable = Observable.of(1,2,3,4,5,6)
            .map { $0 * 10 }
            .subscribe(onNext: {
                print("onNext: ", $0)
            })
```
**出力結果**

```出力：
onNext:  10
onNext:  20
onNext:  30
onNext:  40
onNext:  50
onNext:  60
```

**マーブルダイアグラム**
<img width="778" alt="スクリーンショット 2019-12-10 21.54.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266462/c53f603e-0ab2-5aed-3a78-4202031cc3ce.png">


## flatMap

**処理**
元のObservableのイベント毎に、Observableに変換して、そのObservableが発行するイベントを1つに集約する。


**用途**
非同期処理を扱いたい場合(API通信での画像の読み込み、異常系のアラート表示など)

**コード**
（解説）
1. A~Cの3つの大文字を通知する`Observable<String>`を作成
2. 1つ大文字にa~cの小文字をつけて通知するObservable<String>を3つ作成し`Observable<Observable<String>>`を作成
3. それらのObsevableの通知内容を集約した `Observable<String>` に変換

```swift:
let observable = Observable.of("A","B","C") // 1
        .flatMap { uppercaseChar in
            Observable.of(uppercaseChar + "a",uppercaseChar + "b",uppercaseChar + "c") // 2
        } // 3                                                                                   
        .subscribe(onNext: {                                                               
            print("onNext: ", $0)
        })
```
**出力結果(非同期なので、結果は毎回変化します)**

```
onNext:  Aa
onNext:  Ab
onNext:  Ba <- 非同期に処理が行われる
onNext:  Ac
onNext:  Bb
onNext:  Ca
onNext:  Bc
onNext:  Cb
onNext:  Cc
```

**マーブルダイアグラム**
<img width="1059" alt="スクリーンショット 2019-12-10 22.33.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266462/8a793d2a-ab7e-795c-c638-c2289f6f3e5e.png">



## flatMapFirst
**処理**
イベントを Observable に変換し、常に１つの Observable のイベントしか通知しない。
前の`flatMap`では、非同期処理が可能になり複数のObservableのイベントが1つに集約が可能だが、
`flatMapFirst`では一度 Observable が発行されるとそれが完了するまで、他の Observable は無視する。（完了後は無視しない）
 



**用途**
既に処理中だったら、処理を開始しないという実装（loadingの表示など）


**コード**

```swift:
let observable = Observable.of("A","B","C")
        .flatMapFirst { uppercaseChar in
                Observable.of(uppercaseChar + "a",uppercaseChar + "b",uppercaseChar + "c")
        }
        .subscribe(onNext: {                                                               
            print("onNext: ", $0)
        })
```

**出力結果(非同期なので、結果は毎回変化します)**

```
onNext:  Aa
onNext:  Ab
onNext:  Ac
```

**マーブルダイアグラム**
<img width="1010" alt="スクリーンショット 2019-12-11 10.53.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266462/446a6882-9c42-9cd3-d7d5-13e67e9749a0.png">


## flatMapLatest
これも flatMapFirst と同じくイベントを Observable に変換し、常に１つの Observable のイベントしか通知しないのですが、次の Observable が来るとそちらにスイッチします。
Observable に変換
常に一番新しい Observable を実行

**処理**
前の`flatMapFirst`と同じくイベントを Observable に変換し、常に１つの Observable のイベントしか通知しない。
新たな Observable が発行されると、前の Observable の完了を待たずに新しい方にスイッチする。（常に新しいObservableを実行）

**用途**
一番新しい処理結果を利用したいという実装（文字入力、API通信の結果表示など）

**コード**

```swift:
let observable = Observable.of("A","B","C")
        .flatMapLatest { uppercaseChar in
                Observable.of(uppercaseChar + "a",uppercaseChar + "b",uppercaseChar + "c")
        }
        .subscribe(onNext: {
            print("onNext: ", $0)
        })
```

**出力結果(非同期なので、結果は毎回変化します)**

```
onNext:  Aa
onNext:  Ba
onNext:  Ca
onNext:  Cb
onNext:  Cc
```

**マーブルダイアグラム**
<img width="972" alt="スクリーンショット 2019-12-10 23.12.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266462/f87db663-970e-ee37-cc47-c72f8f2a4624.png">


# おわりに
今回は、RxSwiftを書く上での基礎（のほんの一部）を学習しました。
その中でも`flatMap`, `flatMapFirst`, `flatMapLatest`の違いを理解し説明するのに時間がかかってしまいました。。。
他にも、複数のobservableを合成するオペレーター（merge, combineLatest, zip, withLatestFrom etc..）があるので次回はそちらをまとめてみようと思います！
[Atrae Advent Calendar 2019](https://qiita.com/advent-calendar/2019/atrae) 明日は、料理人からエンジニアに転身した@katou2213が書きます！
よろしくおねがいします！



### 参考
[RxSwift研究読本1 入門編](https://booth.pm/ja/items/1076262)
[ReactiveX Document](http://reactivex.io/documentation/operators.html#transforming)