今回は RxSwift(RxCocoa) でたびたび使用する Subject
・Relay
の違いや Observable
との違いについて簡単にまとめようと思います。また、Trait などはまた別の記事で触れようかと思います。
Subject・Relay とは?
これらのクラスはイベントの検知もできますが、イベントを流すこともできます。また、これも別の記事で書こうと思いますが、Subject
・Relay
クラスは subscribe
(購読) しなくてもストリームが流れるので、Hot な Observable とも言われたりします。また、前回の記事で書いたような subscribeOn
などによって実行する Scheduler を Hot な Observable では制御することはできません。
Subject
Subject
では下記の種類のクラスがあり、それぞれ onNext
・onError
・onCompleted
イベントを流すことができます。
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 //
参考
- http://reactivex.io/documentation/subject.html
- https://github.com/ReactiveX/RxSwift/blob/master/Documentation/Subjects.md
- https://qiita.com/yyokii/items/81dc182dc4a6f1b9fd1f
- https://qiita.com/usamik26/items/f5d522e22bd1e705eef1#_reference-52fa32251d49624c7baa