RxSwiftに取り組み始めた

もくもくと勉強する会（[如法会 その2](https://nyoho.doorkeeper.jp/events/41066)）に参加しています。広島の勉強会ですが、長野の自宅から参加です。

題材はなんでも良いらしいので、前から気になっていたRxSwiftについて学んでみました。

実は以前にもRxSwiftをアプリに組み入れようとしてみたのですが、いざ取り組んでみようとしたらXcodeを前に「で、自分の場合は何から手を付けたら？？」と固まってしまった諦めた経験があるので、この機に基本からやり直すことに決めた次第です。

#やったこと・わかったこと

## ArrayやMapを`Observable()`にする

RxSwiftの土俵に乗るためには、まず何より対象をストリームに乗せるべく、`Observable`化しなければいけません。

ArrayやMapのようなSequenceTypeは、`Array`か`SequenceType`のextensionで定義された`toObservable()`メソッドによって、Observable化できます。

```swift
// Arrayのextensionが使われる
print("\([1,2,3,4,5,6].toObservable())")
// → RxSwift.Sequence<Swift.Int> Array

// SequenceTypeのextensionが使われる
print("\((0...100).toObservable())")
// → RxSwift.Sequence<Swift.Int> 

print("\([0:1, 2:3, 4:5, 6:7].toObservable())")
// → RxSwift.Sequence<(Swift.Int, Swift.Int)>
```

`Array`、`SequenceType`の2種類の`toObservable()`は、どちらも`Observable+Creation.swift`に実装があり、`Sequence`クラスをインスタンス化して返すようになっていました。下は`Array`版のコードです。

```swift
// extension Array
@warn_unused_result(message="http://git.io/rxs.uo")
public func toObservable(scheduler: ImmediateSchedulerType? = nil) -> Observable<Generator.Element> {
    return Sequence(elements: self, scheduler: scheduler)
}
```

他方の`SequenceType`もほとんど同じで、上のコードでelements引数に対して`Array(self)`と配列化していました。`Map`に`toObservable()`を呼ぶと、タプルの配列に変化するようです。

```swift
// extension Array
@warn_unused_result(message="http://git.io/rxs.uo")
public func toObservable(scheduler: ImmediateSchedulerType? = nil) -> Observable<Generator.Element> {
    return Sequence(elements: Array(self), scheduler: scheduler)
}
```

この`scheduler`は、デフォルト引数によって`nil`が渡されていますが、代わりに`ConcurrentMainScheduler`や`SerialDispatchQueueScheduler`も指定できるようです。このへんの使い分け方はまだわかりません。

いちおう`nil`を渡したときの処理を追ってみると、インスタンス化の時点では単にメンバー変数にそのまま渡しているものの、`Sequence`クラスの`subscribe()`メソッド内でスケジューラの有無による別処理が走ることになっていました。コメントにある通り、その場で実行することで、わざわざ`SequenceSink`にご登場いただかなくても済むようになっています。

```swift
// Sequence.swift
class Sequence<E> : Producer<E> {
    :
    override func subscribe<O : ObserverType where O.E == E>(observer: O) -> Disposable {
        // optimized version without scheduler
        guard _scheduler != nil else { // ★nilの場合はここに入る！
            for element in _elements {
                observer.on(.Next(element))
            }
            
            observer.on(.Completed)
            return NopDisposable.instance
        }

        let sink = SequenceSink(parent: self, observer: observer)
        sink.disposable = sink.run()
        return sink
    }
}
```

## 要素を順に読んでいく
Observable化したあとは、RxSwiftの言葉で話します。ArrayやMapの要素を１つずつ読んでいくには`ObservableType`のextension、`subscribe()`メソッドを使います。先ほどの`Sequence.swift`ファイルで出てきました。

```swift
[1,2,3,4,5,6].toObservable()
    .subscribe { event in
        print("\(event)")
        // Event(1) → Event(2) → ... → Completed
    }
    .addDisposableTo(DisposeBag())
```

クロージャに届くのはenumの`Event`で、それぞれの値がenumにラップされているものです。この型はとてもシンプルなもので、デバッグプリントなどを除けば以下で表現できる簡単な型です。

```swift
public enum Event<Element> : CustomDebugStringConvertible {
    case Next(Element)
    case Error(ErrorType)
    case Completed
}
```

上のコードは、実行すると`Event(1) → Event(2) → ... → Completed`というように1行ずつ出力されて終わります。最後に`Completed`が届いているので、きちんとswitchなどでパターンマッチングしてあげないといけないですね。

##後片付け
Rxにおける後片付けは、`DisposeBag`オブジェクトに`addDisposableTo()`することです。それにより、`Completed`が届いたあとに実行中に確保していたリソースは解放され、一連のストリームが終了します。

`DisposeBag()`は`DisposeBag.swift`ファイルで定義されています。各Observable(正確には`Disposable`に従うオブジェクト)のextensionもここで実装してあり、`addDisposable(bag)`メソッドを呼ぶことで、bagが持つ配列に格納するようになっています。

```swift
extension Disposable {
    public func addDisposableTo(bag: DisposeBag) {
        bag.addDisposable(self)
    }
}
```

`DisposeBag`を呼んでみたところ、面白いことに生きている間は何もしないことがわかりました。デイニシャライザで仕事をしていて、これまでaddしてきたDisposableなオブジェクトを配列から取り除き、そのdispose()メソッドを呼ぶようになっていました。

#次にしたいこと

今回は、ここまでです。ArrayやMapをObservableにする方法と、それをsubscribeする方法、そして、最後にDispoaseBag()にて後片付けされることがわかりました。

次回の如法会に参加する場合、flatMapやmapについて知見を深められたらと思います。

以上です。

# 余談：書籍のお知らせ
最後に、知人の書いた本をちょっとだけですが宣伝です。

以前、「[上を目指すプログラマーのためのiPhoneアプリ開発テクニック iOS 7編](http://www.amazon.co.jp/gp/product/B00J3H930O/ref=as_li_ss_tl?ie=UTF8&camp=247&creative=7399&creativeASIN=B00J3H930O&linkCode=as2&tag=ktkt02-22)」などで本を一緒に書いた西方さんが、新しくCore Data+Swiftをテーマにした本「[Swift+Core DataによるiOSアプリプログラミング](http://www.amazon.co.jp/gp/product/4839954887/ref=as_li_ss_tl?ie=UTF8&camp=247&creative=7399&creativeASIN=4839954887&linkCode=as2&tag=ktkt02-22)」を出しました。

<a  href="http://www.amazon.co.jp/gp/product/4839954887/ref=as_li_ss_il?ie=UTF8&camp=247&creative=7399&creativeASIN=4839954887&linkCode=as2&tag=ktkt02-22"><img border="0" src="http://ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=4839954887&Format=_SL160_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=ktkt02-22" ></a><img src="http://ir-jp.amazon-adsystem.com/e/ir?t=ktkt02-22&l=as2&o=9&a=4839954887" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

献本いただいたので私も読んでみたのですが、Core Dataの基本からアプリに組み込む時の実践的な内容までが書かれた、良書になっています。

お近くの本屋で見かけたら、ぜひ手にとってみてはいかがでしょうか。払った値段を超える知識を得られると思います。私もずっと手元に置いておき、調べるのに使っています。