iOSエンジニアのつぶやき

毎朝8:30に iOS 関連の技術について1つぶやいています。まれに釣りについてつぶやく可能性があります。

RxSwift(RxCocoa) における Subject・Relay を理解する

今回は RxSwift(RxCocoa) でたびたび使用する SubjectRelay の違いや Observable との違いについて簡単にまとめようと思います。また、Trait などはまた別の記事で触れようかと思います。

Subject・Relay とは?

これらのクラスはイベントの検知もできますが、イベントを流すこともできます。また、これも別の記事で書こうと思いますが、SubjectRelay クラスは subscribe(購読) しなくてもストリームが流れるので、Hot な Observable とも言われたりします。また、前回の記事で書いたような subscribeOn などによって実行する Scheduler を Hot な Observable では制御することはできません。

yamato8010.hatenablog.com

Subject

Subject では下記の種類のクラスがあり、それぞれ onNextonErroronCompleted イベントを流すことができます。

Subject 内容 初期値
AsyncSubject onCpmpleted が呼ばれた直後に、直前の onNext の値がストリームに流れます。 なし
BehaviorSubject ストリームを購読する際に、直前の値を一度流してから subscribe() します。つまり、購読した際に必ず一度イベントが発生します。 あり
PublishSubject イベントが発生したタイミングで、直前の値をストリームに流します。 なし
ReplaySubject 購読直後に引数で指定した bufferSize の分だけ前の値をストリームに流します。(前の値がない場合は PublishSubject と同じように振る舞います。) なし

AsyncSubject

    let sub = AsyncSubject<String>.init()
    sub
        .subscribe(onNext: { str in
            print(str)
        }).disposed(by: disposeBag)
    
    sub.onNext("1")
    sub.onNext("2")
    sub.onNext("3")
    sub.onCompleted()

    // 出力:
    //
    // 3
    //

BehaviorSubject

    let sub = BehaviorSubject<String>.init(value: "1")
    sub
        .subscribe(onNext: { str in
            print(str)
        }).dispose() // 購読終了

    sub.onNext("2")

    sub
    .subscribe(onNext: { str in
        print(str)
    }).disposed(by: disposeBag)

    sub.onNext("3")
    sub.onCompleted()

    // 出力:
    //
    // 1
    // 2
    // 3
    //

PublishSubject

    let sub = PublishSubject<String>.init()
    sub.onNext("1")
    sub.onNext("2")
    sub
        .subscribe(onNext: { str in
            print(str)
        }).disposed(by: disposeBag)
    sub.onNext("3")
    sub.onCompleted()

    // 出力:
    //
    // 3
    //

ReplaySubject

    let sub = ReplaySubject<String>.create(bufferSize: 2) // 購読直後に2つ前の値をストリームに流す
    sub.onNext("1")
    sub.onNext("2")
    sub.onNext("3")
    sub
        .subscribe(onNext: { str in
            print(str)
        }).disposed(by: disposeBag)
    sub.onNext("4")
    sub.onNext("5")
    sub.onCompleted()

    // 出力:
    //
    // 2
    // 3
    // 4
    // 5
    // 

Relay

Relay には下記のような種類のクラスがあり、流せるイベントは Subject と違い onNext のみイベントとして流すことができます。また、実際にイベントを流す時には accept() という関数を使用します。

Relay 内容 初期値
BehaviorRelay BehaviorSubject と振る舞いは同じで、ストリームを購読する際に、直前の値を一度流してから subscribe() します。 あり
PublishRelay PublishSubject と振る舞いは同じで、イベントが発生したタイミングで直前の値をストリームに流します。 なし

BehaviorRelay

    let relay = BehaviorRelay<String>.init(value: "1")

    relay
        .subscribe(onNext: { str in
            print(str)
        }).dispose() // 購読終了

    relay.accept("2")
    relay.accept("3")

    relay
        .subscribe(onNext: { str in
            print(str)
        })
        .disposed(by: disposeBag)

    relay.accept("4")

    // 出力:
    //
    // 1
    // 3
    // 4
    //

PublishRelay

    let relay = PublishRelay<String>.init()

    relay.accept("1")
    relay.accept("2")

    relay
        .subscribe(onNext: { str in
            print(str)
        })
        .disposed(by: disposeBag)

    relay.accept("3")
    relay.accept("4")

    // 出力:
    //
    // 3
    // 4
    //

参考

その他の記事

yamato8010.hatenablog.com

yamato8010.hatenablog.com

yamato8010.hatenablog.com