4
4

More than 3 years have passed since last update.

俺的RxSwiftまとめ⑤(Subjects/Relayとは?)

Posted at

この記事は、俺的RxSwiftまとめ①,俺的RxSwiftまとめ②,俺的RxSwiftまとめ③(Observableとは何か? - その1),俺的RxSwiftまとめ④(disposebagとは?)の続きです。

Subjectとは何か?

Subjectobserverとしてもobservableとしても動作するもの。
イベントの受け取って処理/イベントを発生させることができるものである。。

PublishSubject

PublishSubjectは、初期値無しの状態でスタートし、subscriberにはsubscribeしてから新しく放出された要素のみを伝えるSubjectである。(ただし、completed/errorは放出された後にsubscribeしたsubscriberにも伝達される。)
マーブルダイアグラムに示すと、
image.png
となる
また、マーブルダイアグラムをコードで表現すると、

PublishSubject.swift
let publishSubject = PublishSubject<String>()
publishSubject.onNext("1")
let subscriber1 = publishSubject
    .subscribe{ event in
        print("subscriber1:" , event.element ?? event)
}
publishSubject.onNext("2")
let subscriber2 = publishSubject
    .subscribe{ event in
        print("subscriber2:" , event.element ?? event)
}
publishSubject.onNext("3")
publishSubject.onCompleted()
let subscriber3 = publishSubject
    .subscribe{ event in
        print("subscriber3:" , event.element ?? event)
}
出力
subscriber1: 2
subscriber1: 3
subscriber2: 3
subscriber1: completed
subscriber2: completed
subscriber3: completed

となる。

どんな時に使われるのか?

PublishSubjectは新しいイベントをsubscriberに通知する時に便利なので、ユーザーのクリックに応じた更新などに用いられる。また、リアルタイム性に優れているので、頻繁にやり取りが行われるチャット等に応用が考えられる。

BehaviorSubject

BehaviorSubjectPublishSubjectreplay(=最新のイベントをsubscriberに伝達すること)の概念を付け加えたもの。そのため、初期値がないとreplayできずエラーとなります。初期値を持たせるか、elementoptionalとして定義することが必須となる。

マーブルダイアグラムに示すと、
image.png
となる。
また、マーブルダイアグラムをコードで表現すると、

BehaviorSubject.swift
let behaviorSubject = BehaviorSubject<String>(value: "1")
let subscriber1 = behaviorSubject
    .subscribe{ event in
        print("subscriber1:" , event.element ?? event)
}
behaviorSubject.onNext("2")
let subscriber2 = behaviorSubject
    .subscribe{ event in
        print("subscriber2:" , event.element ?? event)
}
behaviorSubject.onNext("3")
behaviorSubject.onCompleted()
let subscriber3 = behaviorSubject
    .subscribe{ event in
        print("subscriber3:" , event.element ?? event)
}
出力
subscriber1: 1
subscriber1: 2
subscriber2: 2
subscriber1: 3
subscriber2: 3
subscriber1: completed
subscriber2: completed
subscriber3: completed

どんな時に使われるのか?

BehaviorSubjectはビューにSubjectの最新の状態を表せるので、placeholderに最新の値をあらかじめ入れておく、ロード中のインジケーターを示す等の場面で用いられる。

ReplaySubject

BehaviorSubjectでは、最新のイベントのみをsubscriberに伝達できたが、ReplaySubjectはバッファサイズに指定した数だけイベントを伝達することができる。ただし、バッファサイズを大きくしたり、画像のようなデータサイズが大きいものを使いすぎると、メモリ逼迫の原因となるので注意が必要である。
マーブルダイアグラムに示すと、
image.png
となる
また、マーブルダイアグラムをコードで表現すると、

ReplaySubject.swift
let replaySubject = ReplaySubject<String>.create(bufferSize: 2)
replaySubject.onNext("1")
replaySubject.onNext("2")
let subscriber1 = replaySubject
    .subscribe { event in
        print("subscriber1:", event.element ?? event)
}
replaySubject.onNext("3")
出力
subscriber1: 1
subscriber1: 2
subscriber1: 3

となる。

どんな時に使われるのか?

以前との差分を取りたい時などに使われる。

AsyncSubject

AsyncSubjectは、completedが流れた直後に、最後の値をsubscriberに渡すもの。
マーブルダイアグラムに示すと、
image.png
となる。

これをコードで表すと、

AsyncSubject.swift
let asyncSubject = AsyncSubject<String>()
asyncSubject.onNext("1")
let subscriber1 = asyncSubject
    .subscribe { event in
        print("subscriber1:", event.element ?? event)
}
asyncSubject.onNext("2")
let subscriber2 = asyncSubject
    .subscribe { event in
        print("subscriber2:", event.element ?? event)
}
asyncSubject.onNext("3")
asyncSubject.onCompleted()
出力
subscriber1: 3
subscriber2: 3
subscriber1: completed
subscriber2: completed

となる。

どんな時に使われるのか?

APIのコールバックを受ける時に便利

Relayとは何か?

Relayは、subjectsラッパーのことである。ラッパーとして果たす役割は、errorcompletedを受け付けず、accept(_:)nextで流れるelementのみを通すことである。

PublishRelayPublishSubject,BehaviorRelayBehaviorSubjectに対応している。
コードに示すとそれぞれ、以下のようになる。

PublishRelay.swift
let publishRelay = PublishRelay<String>()

let disposeBag = DisposeBag()
publishRelay.accept("1")
publishRelay
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)

publishRelay.accept("2")
出力
2
BehaviorRelay.swift
let behaviorRelay = BehaviorRelay(value: "Initial value")
let disposeBag = DisposeBag()

behaviorRelay.accept("1")

behaviorRelay
    .subscribe {
        print("subscriber1:" , $0.element ?? $0)
}
.disposed(by: disposeBag)

behaviorRelay.accept("2")

behaviorRelay
    .subscribe {
        print("subscriber2:", $0.element ?? $0)
}
.disposed(by: disposeBag)

behaviorRelay.accept("3")
出力
subscriber1: 1
subscriber1: 2
subscriber2: 2
subscriber1: 3
subscriber2: 3

となる。

4
4
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
4
4