RxSwift の Cold Observable と Hot Observable の違いを理解する

  • 22
    Like
  • 0
    Comment
More than 1 year has passed since last update.

RxSwift と ReactiveCocoa の違いとして Cold Observable と Hot Observable を統一的に扱えるか/そうでないかという点があります:

http://stackoverflow.com/questions/32542846/reactivecocoa-vs-rxswift-pros-and-cons:

RAC states that the separation of hot/cold observable was necessary and that is the core feature of the framework, RxSwift says that the unification of them is better than the separation, again it's just about how side effects are managed/performed.

RxSwiftで両者がどのように扱われているのか気になったので調べました。

Cold Observable と Hot Observable とは何か

ひとことでいうと Cold Observable は遅延評価される sequence のことで、 Hot Observable は早期評価される sequence のことです。
Cold Observable は subscribe されたタイミングでsequence を評価しますが、Hot observable は create されたタイミングで評価します。

> http://www.introtorx.com/content/v1.0.10621.0/14_HotAndColdObservables.html:

The lazily-evaluated sequence did not have to yield any more values than required. Lazy evaluation is good for on-demand queries whereas eager evaluation is good for sharing sequences so as to avoid re-evaluating multiple times. Implementations of IObservable can exhibit similar variations in style.

RxSwift で Observable を生成すると Cold になるのか Hot になるのか

Introduction Rx では Observable.Create で生成した Observable は Cold になっているようでした:

calling the method does nothing. Subscribing to the returned IObservable will however invoke the create delegate which connects to the database.

とはいえ RxSwift でどうなっているのか気になったのでコードを見てみました。

RxSwift の create メソッドの実装を追う

まず、create メソッドの実装としては subscribeクロージャを AnonymousObservable に渡しています:

public func create<E>(subscribe: (AnyObserver<E>) -> Disposable) -> Observable<E> {
   return AnonymousObservable(subscribe)
} 

この subscribe クロージャは AnonymousObservable の subscribeHandler プロパティに渡ります:

public class AnonymousObservable<Element> : Producer<Element> {

public init(_ subscribeHandler: SubscribeHandler) {
       self.subscribeHandler = subscribeHandler
   }

こうして create された AnonymousObservable は subscribeNext メソッドを受け取ることになります。
この subscribeNext メソッドの実装としては AnonymousObservable のスーパークラスである Producer の subscribe に行き着きます:

public override func subscribe<O : ObserverType where O.E == Element>(observer: O) -> Disposable {

(edited)

       if !CurrentThreadScheduler.isScheduleRequired {
           let disposable = run(observer, cancel: subscription, setSink: setSink)

           subscription.disposable = disposable
       }
       else {
           CurrentThreadScheduler.instance.schedule(sink) { sink in
               let disposable = self.run(observer, cancel: subscription, setSink: setSink)
               subscription.disposable = disposable
               return NopDisposable.instance
           }
       }

       return d
   }

このなかの run メソッドが AnonymousObservableSink の run メソッドに行き着き、そこで subscribeHandler プロパティをコールしているようです:

class AnonymousObservableSink<O: ObserverType> : Sink<O>, ObserverType {

    func run(parent: Parent) -> Disposable {
        return parent._subscribeHandler(AnyObserver(self))
    }

この subscribeHandler こそが もともとは create メソッドの引数として渡ったクロージャでした。
クロージャの実行は create メソッド実行のタイミングではなく、 subscribe メソッド実行のタイミングになっていることがわかりました。

まとめ

  • RxSwift では create メソッドで Cold Observable を生成する

なお、Hot Observable の生成についてはまた調べます。