はじめてのRxSwiftのメモ

## はじめに
これは僕がRxSwiftを学んでいる過程で覚えたことに関する覚書です。

## インストール
[RxSwiftのGithub](https://github.com/ReactiveX/RxSwift)からソースをダウンロードします。
中に`Playground`が入っているので、こちらを起動できるようにします。

`RxExample`をコンパイルする必要があるので、そちらをコンパイルすると`Playground`が使えるようになります。

## Observableって？
初めてReact系のプログラムを触ると、ここから分からなくなります。
僕がそうでしたし、今でも完全に把握しているとはとても言えません。（なので、この覚書を書いています。）
ここでは僕なりに把握した内容を書いておきます。（間違いなどがありましたらご指摘願います。）

`Observable`は`送るオブジェクト`を複数保持しているものです。
一方で`subscribe`は受信するメソッドになります。

例えば、`[1,2]`というオブジェクトを送って受信する場合は以下のようになります。

```swift
let sequenceFromArray = [1, 2].toObservable()

let subscription = sequenceFromArray
    .subscribe { event in
        print(event)
    }
```

何も面白くないプログラムですが、これが基本的な形になります。

## subscribeって？
`subscribe`は送られたデータを受け取る処理になります。
コードは上記に書いた通りです。

ただ、上記のコードで受け取った場合はデータをアンラップできてないので実際に中身を取得する場合は以下のようになります。

```swift
let sequenceFromArray = [1, 2].toObservable()

let subscription = sequenceFromArray
    .subscribe { event in
        switch event {
        case .Next(let value):
            print(value)
        default:
            print(event)
        }
    }
```

もしくは`subscribeNext`を使用します。


```swift
let sequenceFromArray = [1, 2].toObservable()

let subscription = sequenceFromArray
    .subscribeNext { value in
        print(value)
    }
```

※`flatMap`や`map`については後述します。

## 何が良いのか？
これだけでは、何も良いことがありません。

```swift
[1, 2].map {
    print($0)
}
```

と同じことしかできません。
ここで出番となるのが`Observable`の性質です。

`Observable`はデータを送信できるというところがポイントになります。
すなわち、これらの事が非同期で行えるという事が`RxSwift`の利点になります。

## PublishSubjectを使って見る
簡易的に使える`PublishSubject`を使って`Observable`を作ってみます。

```swift
let subject = PublishSubject<String>()
// subscribeを先に行う。
subject.subscribeNext{ (value) -> Void in
    print(value)
}

// データを送信する。
subject.on(.Next("a"))
subject.on(.Next("b"))
subject.on(.Next("c"))
subject.on(.Next("d"))
// -> a,b,c,dが出力される。
```

データの受信部分を先に定義してから、送信するデータをあとで定義しています。
このように行う事で、処理の受信部分から定義する事ができます。

・・・という事は、上記の`subject`オブジェクトをAPIの処理に渡せば結果が返ってきた時点で`subscribeNext`が発火する事になります。
例えばチャットルームの人数などをリアルタイムに切り替える場合などに使えそうです。

※実際に使う場合は`[weak self]`などが必要になると思いますが、本記事では割愛します。

### いつ解放されるの？
もう一つ重要なのが`subject`している関数がいつ解放されるかというところです。

```swift
subject.onCompleted()
subject.onError(ErrorType.OriginalError)
```

送信側で上記の`Completed`もしくは`Error`が送信されると解放されます。
※その際に処理を行う場合は`subscribeCompleted`や`subscribeError`などでイベントを拾えます。`subscribe`メソッドで全てを一括定義する事もできます。

受信側では`subject`オブジェクトを保持して`dispose`を行う事で`subscribe`を止める事ができます。

```swift
subject.dispose()
```

### 自動解放はできないの？
完全な自動解放はできないのですが、変数のスコープを利用した解放ならできます。
例えば以下のようなコードになります。

```swift
class Example {
    let disposeBag = DisposeBag()

    func subject() -> PublishSubject<String> {
        let subject = PublishSubject<String>()
        subject.subscribeNext({ (value) -> Void in
            print(value)
        }).addDisposableTo(disposeBag)
        return subject
    }
}
```

`disposeBag`という変数に`DisposeBag`オブジェクトを保持させて`addDisposableTo`でオブジェクトを付与させておけば、`disposeBag`が解放されたタイミング（classが破棄されるなど）で`subscribe`が止まります。

## Observable.create
`PublishSubject`を使っても汎用的に使えますが、`subject`オブジェクトを持っているところ全てでデータを送信できてしまうのでコードが読みにくくなります。
また、下手に弄られると予期せぬところでデータを送信されてしまうため堅牢なプログラムを作る事が困難になります。

その場合は`Observable.create`であらかじめ`Observable`を作って渡したほうが堅牢になります。

```swift
class Api {
    func request() -> Observable<Int> {
        Observable<Int>.create {obj in
            // APIに対してリクエストして、結果がIntで返ってくるとする。
            Server.request { (value) in
                obj.onNext(value)
            }
            // createの返却値は「おまじない」として以下のように書いておけば、大抵問題ないはず。
            return NopDisposable.instance
        }
    }
}

class Receiver {
    func hoge() {
        Api.request().subscribeNext({ (value) -> Void in
            print(value)
        })
    }
}
```

このように`Observable<Int>.create`を使って`Observable`を返す事で、処理内容を隠蔽して返す事ができます。

## flatMap
また、処理の途中で内容を変えたい場合はflatMapが便利です。

```swift
Api.request().flatMap {  (value) -> Observable<(Int, String)>
    return Observable.just((value, "str: \(value)"))
}.subscribeNext({ (value, str) -> Void in
    print(value, str)
}
```

処理結果に対して文字列の結果もタプルで返す例です。
flatMap内でjsonの解析や別のAPIを呼び出す事もできます。（非同期にする場合は再度`Observable.create`を作成して返してあげます。）

## その他
それ以外にも以下のようなものが標準で用意されているので、使いこなすととても便利です。

* `Observable.combineLatest`両方の結果が返ってくるまで待機している。両方そろった後に片方の結果が返ってきても呼び出される。
* `Observable.zip`両方の結果が返ってくるまで待機している。両方そろった後に片方の結果が返ってきても呼び出されず、もう一方の結果を待つ。
* `distinctUntilChanged`結果が変わらない場合は呼び出さないようにする。
* `.debounce(0.7, scheduler: MainScheduler)`一定時間毎に結果を取得する。（インクリメントサーチなどで使える。）

etc...

## 最後に
上級者から見れば初歩的な事ですが、僕にとってはこれらの事もわからなかったので他の誰かの役に立てば幸いです。