RxSwift は非同期イベントを受け取るための枠組みです(なお、RxSwift 再入門 という記事も書いていますので、よろしければどうぞ)。
非同期イベントと言いましたが、これは文字通り同期的でないイベントですので、現在のスレッドとは別のスレッドで発生するものです。では、RxSwift でスレッドはどのように扱われるのでしょうか?
Rx でスレッドに当たる概念がスケジューラです。
(正確にはスレッドと完全に対応する関係ではないのですが、多くの場合は1つのスケジューラに1つのスレッドを対応させます。この記事ではそのあたりの詳細は省きます)
余談:Rx の三要素
Rx において重要な要素が3つあります。
- Observable
- Operator
- Scheduler
スケジューラは、Rx の三要素のひとつです。
スケジューラを使う
Observable と Observer
まず、イベント発生元(Observable)とイベント処理(Observer)とを分けて考えます。
hogeObservable // ここはイベント発生元(Observable)
.do(onNext: { _ in
// ここもイベント発生元(Observable)
})
.subscribe(onNext: { _ in
// ここはイベント処理(Observer)
})
このそれぞれについて、スケジューラを指定することができます。
observeOn
observeOn
を使うと、イベント処理のスケジューラを変えることができます。
hogeObservable
.observeOn(MainScheduler.instance)
.subscribe(onNext: { _ in
// メインスレッドで動作する
})
例えば、イベント処理で UI 操作をしたい場合にメインスレッドで処理する、という使い方があります。
subscribeOn
subscribeOn
を使うと、イベント発生元のスケジューラを変えることができます。
hogeObservable
.subscribeOn(hogeScheduler)
.do(onNext: { _ in
// hogeScheduler で動作する
})
.observeOn(MainScheduler.instance)
.subscribe(onNext: { _ in
// メインスレッドで動作する
})
例えば、イベント発生元は Web API 実行スレッドやデータベースアクセススレッドで処理をする、という使い方があります。
スレッド制御まとめ
-
subscribeOn
: イベント発生元(Observable)のスケジューラ指定 -
observeOn
: イベント処理(Observer)のスケジューラの指定
注意点
実は subscribeOn
で切り替えできない場合があります。それは Observable の性質によるものです。次のセクションで詳しく述べます。
Hot と Cold
subscribeOn が効かない場合
Observable には、Hot なものと Cold なものとの2種類があります。
- Hot な Observable は
subscribeOn
で切り替えできない - Cold な Observable は
subscribeOn
で切り替えできる
例:切り替えできないケース
let hogeRelay = BehaviorRelay(value: "A")
let hogeThread = Thread() {
sleep(1)
hogeRelay.accept("B")
sleep(1)
hogeRelay.accept("C")
}
hogeThread.start()
hogeRelay
.subscribeOn(MainScheduler.instance)
.do(onNext: { _ in
// hogeThread で accept したものは hogeThread で動作(subscribeOn が効いていない)
})
.observeOn(MainScheduler.instance)
.subscribe(onNext: { _ in
// メインスレッドで動作する
})
このケースでは、イベント発生元は subscribeOn
で指定したスケジューラとは無関係なスレッドで動作します。
ここでは、BehaviorRelay
が Hot な Observable であるために、subscribeOn
が効いていません。
Observable の分類 : Hot / Cold
Hot と Cold の性質の違いは以下のとおりです。
- Hot
-
subscribe
しなくてもストリームが流れる -
subscribeOn
で制御できない
-
- Cold
-
subscribe
したらストリームが流れ出す -
subscribeOn
で制御できる
-
Hot と Cold な Observable は、具体的には以下のものです。
- Hot
- Subject や Relay
- Rx の外側からストリームにイベントを送れる
- Cold
- 上記以外はだいたい Cold
- Rx の制御下にある
Hot / Cold についての私見
私見ですが、Cold な Observable が「普通のもの」、Hot が「特殊なもの」であると考えています。
Cold な Observable は Rx の外側によって操作されることがなく、Rx の制御下にあります。そのおかげで、Rx の仕組みである subscribe
や subscribeOn
で制御が可能です。それができない Hot なものは特殊な存在と感じられます。
ただ一方で、Cold なものだけでは実用上不便そうです。実際に、データバインディング目的で RxSwift を使う場合に、Subject や Relay といった Hot なものは多用します。
そういうわけなので、Cold なものとも Hot なものとも上手につきあうのが良いかと思っています。
補足
この記事は、先日 Mobile Act OSAKA #6 で発表した RxSwiftのスケジューラ をベースに、整理して文章として書き直したものです。