48
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

RxSwift のスケジューラ

Posted at

RxSwift は非同期イベントを受け取るための枠組みです(なお、RxSwift 再入門 という記事も書いていますので、よろしければどうぞ)。

非同期イベントと言いましたが、これは文字通り同期的でないイベントですので、現在のスレッドとは別のスレッドで発生するものです。では、RxSwift でスレッドはどのように扱われるのでしょうか?

Rx でスレッドに当たる概念がスケジューラです。

(正確にはスレッドと完全に対応する関係ではないのですが、多くの場合は1つのスケジューラに1つのスレッドを対応させます。この記事ではそのあたりの詳細は省きます)

余談:Rx の三要素

Rx において重要な要素が3つあります。

  • Observable
  • Operator
  • Scheduler

スケジューラは、Rx の三要素のひとつです。

スケジューラを使う

Observable と Observer

まず、イベント発生元(Observable)とイベント処理(Observer)とを分けて考えます。

Observable.png

hogeObservable // ここはイベント発生元(Observable)
    .do(onNext: { _ in
        // ここもイベント発生元(Observable) 
    })
    .subscribe(onNext: { _ in
        // ここはイベント処理(Observer)
})

このそれぞれについて、スケジューラを指定することができます。

Scheduler.png

observeOn

observeOn を使うと、イベント処理のスケジューラを変えることができます。

observeOn.png

hogeObservable
    .observeOn(MainScheduler.instance)
    .subscribe(onNext: { _ in
        // メインスレッドで動作する
})

例えば、イベント処理で UI 操作をしたい場合にメインスレッドで処理する、という使い方があります。

subscribeOn

subscribeOn を使うと、イベント発生元のスケジューラを変えることができます。

subscribeOn.png

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 の仕組みである subscribesubscribeOn で制御が可能です。それができない Hot なものは特殊な存在と感じられます。

ただ一方で、Cold なものだけでは実用上不便そうです。実際に、データバインディング目的で RxSwift を使う場合に、Subject や Relay といった Hot なものは多用します。

そういうわけなので、Cold なものとも Hot なものとも上手につきあうのが良いかと思っています。

補足

この記事は、先日 Mobile Act OSAKA #6 で発表した RxSwiftのスケジューラ をベースに、整理して文章として書き直したものです。

48
34
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
48
34

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?