RxSwift 入門 その2
RxSwift 入門 その1 - タコさんブログ の続き。
今回は、RxSwiftプレイグラウンドのSubjectsの項。
Subject は Observer 、また Observable の両方として機能し、Hotなオブザーバブルである。
Erik MeijerはSubjectを好んでいないようだ(Why Does E.Meijer not like Subjects?)。
Subjects
RxSwiftでは以下のSubjectクラスが利用できる。
- PublishSubject
- ReplaySubject
- BehaviorSubject
- Variable
PublishSubject
PublishSubjectはサブスクリプションの後のソースObservable(s)が送信したアイテム(イベント)のみを送信する。
// メモリ管理 let disposeBag = DisposeBag() // PublishSubject生成 let subject = PublishSubject<String>() // サブスクライブ subject.subscribe({ event in print("Subscription: 1, event:\(event)") }).addDisposableTo(disposeBag) subject.on(.Next("a")) subject.on(.Next("b")) // "b"を送信した後に、 // 更にサブスクライブ subject.subscribe({ event in print("Subscription: 2, event:\(event)") }).addDisposableTo(disposeBag) subject.on(.Next("c")) subject.on(.Next("d"))
この出力は、
Subscription: 1, event:Next(a) Subscription: 1, event:Next(b) Subscription: 1, event:Next(c) Subscription: 2, event:Next(c) Subscription: 1, event:Next(d) Subscription: 2, event:Next(d)
ReplaySubject
ReplaySubjectはオブザーバがいつサブスクライブするかに関わらずソースObservable(s)が送信した全てのアイテム(イベント)をオブザーバに送信する。
// メモリ管理 let disposeBag = DisposeBag() // ReplaySubject生成 // bufferSizeに指定した数だけアイテムがキャッシュされる // 全てのアイテムをキャッシュする場合は、createUnbounded を使用する let subject = ReplaySubject<String>.create(bufferSize: 1) // サブスクライブ subject.subscribe({ event in print("Subscription: 1, event:\(event)") }).addDisposableTo(disposeBag) subject.on(.Next("a")) subject.on(.Next("b")) // "b"を送信した後に、 // 更にサブスクライブ subject.subscribe({ event in print("Subscription: 2, event:\(event)") }).addDisposableTo(disposeBag) subject.on(.Next("c")) subject.on(.Next("d"))
この出力は、
Subscription: 1, event:Next(a) Subscription: 1, event:Next(b) Subscription: 2, event:Next(b) Subscription: 1, event:Next(c) Subscription: 2, event:Next(c) Subscription: 1, event:Next(d) Subscription: 2, event:Next(d)
BehaviorSubject
オブザーバがBehaviorSubjectをサブスクライブした時、ソースObservableから送信された最新のアイテム(イベント)を送信し、それから、ソースObservableから送信された他のアイテムを送信し続ける。
// メモリ管理 let disposeBag = DisposeBag() // BehaviorSubject生成 // 初期値 "Initial value" を与える let subject = BehaviorSubject<String>(value: "Initial value") // サブスクライブ subject.subscribe({ event in print("Subscription: 1, event:\(event)") }).addDisposableTo(disposeBag) subject.on(.Next("a")) subject.on(.Next("b")) // "b"を送信した後に、 // 更にサブスクライブ subject.subscribe({ event in print("Subscription: 2, event:\(event)") }).addDisposableTo(disposeBag) subject.on(.Next("c")) subject.on(.Next("d")) subject.on(.Completed)
この出力は、
Subscription: 1, event:Next(Initial value) Subscription: 1, event:Next(a) Subscription: 1, event:Next(b) Subscription: 2, event:Next(b) Subscription: 1, event:Next(c) Subscription: 2, event:Next(c) Subscription: 1, event:Next(d) Subscription: 2, event:Next(d) Subscription: 1, event:Completed Subscription: 2, event:Completed
Variable
VariableはBehaviorSubjectをラップする。BehaviorSubjectに対しての利点は、Variableは明示的に complete または error になることがない。また、Variableはdeallocated時に自動的に完了する。
// Variable のdeallocate時にCompleteを見るためにdoで囲む do { // メモリ管理 let disposeBag = DisposeBag() // Variable生成 // 初期値 "Initial value" を与える let variable = Variable("Initial value") variable.asObservable().subscribe({ event in print("Subscription: 1, event:\(event)") }).addDisposableTo(disposeBag) variable.value = "a" variable.value = "b" // valueを"b"に変更した後に、 // 更にサブスクライブ variable.asObservable().subscribe({ event in print("Subscription: 2, event:\(event)") }).addDisposableTo(disposeBag) variable.value = "c" variable.value = "d" print("--- スコープを抜けて variable はdeallocateされる ---") }
この出力は、
Subscription: 1, event:Next(Initial value) Subscription: 1, event:Next(a) Subscription: 1, event:Next(b) Subscription: 2, event:Next(b) Subscription: 1, event:Next(c) Subscription: 2, event:Next(c) Subscription: 1, event:Next(d) Subscription: 2, event:Next(d) --- スコープを抜けて variable はdeallocateされる --- Subscription: 1, event:Completed Subscription: 2, event:Completed