RxSwiftを理解するためにオペレータを整理してみた

# はじめに

RxSwiftには多くのオペレータが登場し、慣れるまでその理解が大変です。
そこで今回、RxSwift研究読本1と2を読んで登場したオペレータや、そのほか基本的なオペレータを整理してみました。
書籍の中では実装やテスト方法についても書かれているので、詳しくはそちらを読んでみると良いと思います。

# オペレータ
## 正常系

### filter
条件に合うもののみにフィルタリングする。

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

### take
イベントを最初の指定した数だけに絞り、指定数に達した時点でcompletedになる。

### map
新しいObservableインスタンスを返す。

### flatMap
mapとの違い、型パラメータとしてObservableConvertibleTypeに準拠している必要があり、その返り値もそれに準拠している必要がある。


### flatMapLatest
flatmapと違い、最新でないイベントを破棄する。

### zip
複数のObservableを順番に組み合わせる。注意として一方のみの値が変っても更新されず、最新状態ではないことを認識しておく必要がある。

### combineLatest
可変長でObservableを引数にとり、最後の引数にresultSelectorをとる。resultSelectorでは、各Observableの値が変わるたびに、その戻り値を次へと流れるObservableを返す。

### withLatestFrom
combineLatestと違って、イベントの発行タイミングは最初のObservable の発行タイミング。


## エラー系

### retry
ストリームからのエラー通知時に、それをオブザーバーに通知せず、自動でストリームを再購読する。

### catchError
Observableを返すことで、エラーを書き換えることができる。
エラーに応じて、自由にストリームを返したい場合や何も返したくない場合に使用する。


### catchErrorJustReturn
catchErrorJustReturnは、catchErrorのラッパーとなっている。
任意の要素に書き換えたい場合に使用する。

```swift:RxSwift/Observables/Catch
extension ObservableType {
    public func catchError(_ handler: @escaping (Swift.Error) throws -> Observable<E>)
    -> Observable<E> {
    return Catch(source: asObservable(), handler: handler)
    }

    public func catchErrorJustReturn(_ element: E)
    -> Observable<E> {
       return Catch(source: asObservable(), handler: { _ in Observable.just(element) })
     }
}
```

## ストリームの分岐

### materialize

Observable<T>としてたonNextイベントとonErrorイベントを一つの、Observable<Event<T>>として変換する。
２個のストリームを作成することで、正常系と異常系に関して、別々に購読できるようになる。

```swift
let observable = Observable<String>.create { observer in
     observer.onNext("A")
     observer.onError(TestError.test)

     return Disposables.create()
 }

_ = observable.materialize()
    .subscribe(onNext: { (event: Event<String>) in
        switch event {
        case .next(let value):
            print("value: \(value)")
        case .error(let error):
            print("error: \(error)")
        case .completed:
            break
        }
    }, onError: {
        print("onError, onError: \($0)")
    }, onCompleted: {
        print("onCompleted:")
    })
```
ただ正常系と異常系の分岐を、毎回書くのは面倒なので、後述するcompactMapを使用したextensionを作成すると良い。


### compactMap
RxSift5.0で追加。

filterおよびmapメソッドをcompactMapメソッドでの書き換えでき、compactMapオペレータは、要素のnilをfilterしてmapしたストリームに変換してくれる。

```swift
extension ObservableType where Element: EventConvertible {

    public func elements() -> Observable<Element.Element> {
      return filter { $0.event.element != nil }
          .map { $0.event.element! }
    }

    public func errors() -> Observable<Swift.Error> {
       return filter { $0.event.error != nil }
          .map { $0.event.error! }
    }
}
```

```swift
extension ObservableType where Element: EventConvertible {

    public func elements() -> Observable<Element.Element> {
        return compactMap { $0.event.element }
    }

    public func errors() -> Observable<Swift.Error> {
        return compactMap { $0.event.error }
    }
}
```

#### Single等では、materializeオペレータがそのままは使えない

ObservableTypeに準拠していないSingleなどの、PrimitiveSequence型は"そのまま"ではmaterializeオペレータを使用できない。

* PrimitiveSequence型
    * Single
        * 成功か失敗のみ送信できる
        * 完了は送信できない
        * いずれかのイベントを送信すると、disposeされる
    * Maybe
        * 成功、失敗、完了を送信することができる
        * いずれかのイベントを送信すると、disposeされる。
 
    * Completable
        * 完了か失敗のみ送信できる。
        * 成功は送信できない
        * いずれかのイベントを送信すると、disposeされる。
        
PrimitiveSequenceのStructとして、Single、Maybe、Completableは実装されている。
ジェネリクスでTraitsを切り替えることで、それらTraits(Single、Maybe、Completable)の振る舞いをするようになっている。
これらのTraitsはストリームを内部に保持したラッパーのため、materializeオペレータを使用できない。

そのためRxSwiftでは、PrimitiveSequenceのasObservable()で取り出せるように実装されている。

```swift:RxSwift/Traits/PrimitiveSequence
extension PrimitiveSequence: ObservableConvertibleType {
    /// Type of elements in sequence.
    public typealias E = Element

    /// Converts `self` to `Observable` sequence.
    ///
    /// - returns: Observable sequence that represents `self`.
    public func asObservable() -> Observable<E> {
        return source
    }
}
```

# 参考

[RxSwift研究読本1 入門編](https://booth.pm/ja/items/1076262)
[RxSwift研究読本2 エラーハンドリング編](https://swift.booth.pm/items/1121167)
https://qiita.com/k5n/items/e80ab6bff4bbb170122d
https://qiita.com/moaible/items/de94c574b25ea4f0ef17
https://qiita.com/k5n/items/17f845a75cce6b737d1e
https://qiita.com/crea/items/d46360e1eac709d6a632
https://qiita.com/bouzuya/items/d019c3eae5db19e395cd