⚠️ 執筆時点の RxSwift バージョンは 3.4.1 です
RxSwift の基本的な用語に対しての大きな変更はあまり無いと思いますが、バージョンの違いによってちょっとインターフェイスが変わっているところがあるので注意してください。
Overview
ReactiveExtension のざっくり説明と、RxSwift でよく使う用語のまとめです。
文字リンクはソースコード、📖はドキュメントへのリンクになっています。
ReactiveExtension / RxSwift
ReactiveExtension
ReactiveX is a combination of the best ideas from
the Observer pattern, the Iterator pattern, and functional programming
http://reactivex.io/
RxSwift
-
Observable(ObservableType) は実質Sequence -
Observable.subscribeは実質Sequence.makeIterator -
ObserverはIteratorのnext()を呼び出す代わりにObservableをsubscribeすることでSequenceの要素を受け取る
enum Event<Element> {
case next(Element) // next element of a sequence
case error(Swift.Error) // sequence failed with error
case completed // sequence terminated successfully
}
class Observable<Element> {
func subscribe(_ observer: Observer<Element>) -> Disposable
}
protocol ObserverType {
func on(_ event: Event<Element>)
}
Observable
subscribe
Observer を渡すかクロージャを渡して subscribe する
someObservable
.subscribe { event in
switch event {
case .next(let value):
// do something
case .error(let error):
// handle error
case .completed:
// do something
}
}
Operators
map, flatMap, filter, scan, take, merge, zip, concat, ...
オペレータ一覧 📖
Cold / Hot 📖
Cold Observable
-
subscribeされて初めてイベントが流れ出す -
Observerがsubscribeする度に別々のストリームが生成される - Async operations, HTTP Connections, TCP connections, streams
Hot Observable
-
subscribeされてなくてもイベントが流れている - 一つのストリームを複数の
Observerがsubscribeできる - Hot な
Observableはconnectするとイベントが流れ出す (subscribeされていようとされていまいと) - RxSwift では
ConnectableObservableは Hot - Variables / properties / constants, tap coordinates, mouse coordinates, UI control values, current time
publish / refCount / replay
publish 📖
-
Observableを Hot (ConnectableObservable) に変換する- 内部的には
multicastを呼んでPublishSubject(後述) にObservableをくっつけてる
- 内部的には
replay(n) 📖
-
Observableを Hot (ConnectableObservable) に変換する- 内部的には
multicastを呼んでReplaySubject(後述) にObservableをくっつけてる
- 内部的には
-
subscribeするとこれまで流れていたイベントが n 個まとめて再度流れてくる
refCount 📖
- Hot な
ObservableをRefCountというObservableでラップする -
RefCountをsubscribeするとラップされた Hot なObservableのconnectが呼び出されて値が流れ出し、RefCountをsubscribeしているObserverがひとりも居なくなるとラップされた Hot なObservableがdisposeされる
share
publsh().refCount()
shareReplay(n)
replay(n).refCount()
shareReplayLatestWhileConnected
大体 shareReplay(1) と同じだけど observer が居なくなったら replay バッファをクリアするやつ
Traits 📖
色々な Observable
Single
一度だけ next が流れてくるという決まりの Observable で、 next が来たらその後すぐ copmleted も流れてくる
public enum SingleEvent<Element> {
/// One and only sequence element is produced. (underlying observable sequence emits: `.next(Element)`, `.completed`)
case success(Element)
/// Sequence terminated with an error. (underlying observable sequence emits: `.error(Error)`)
case error(Swift.Error)
}
Completable
値を持った next は無く completed のみ流れてくる決まりの Observable
public enum CompletableEvent {
/// Sequence terminated with an error. (underlying observable sequence emits: `.error(Error)`)
case error(Swift.Error)
/// Sequence completed successfully.
case completed
}
Maybe
一度だけ next が流れてくる or completed のみ流れてくる決まりの Observableで、next が来たらその後すぐ copmleted も流れてくる
public enum MaybeEvent<Element> {
/// One and only sequence element is produced. (underlying observable sequence emits: `.next(Element)`, `.completed`)
case success(Element)
/// Sequence terminated with an error. (underlying observable sequence emits: `.error(Error)`)
case error(Swift.Error)
/// Sequence completed successfully.
case completed
}
Driver (RxCocoa)
-
Observerの処理をMainSchedulerで実行 - エラーは無視
-
shareReplayLatestWhileConnected()する - UI イベントを扱うのに使うとコードがスッキリする
Observer.asDriver(onErrorJustReturn: []) は下記と同じ
let safeSequence = someObservable
.observeOn(MainScheduler.instance) // observe events on main scheduler
.catchErrorJustReturn(onErrorJustReturn) // can't error out
.shareReplayLatestWhileConnected // side effects sharing
return Driver(raw: safeSequence) // wrap it up
Relay (RxCocoa)
- replay しない Driver
-
RxSwift 4 の Signal と Relay - Qiita
ControlProperty / ControlEvent (RxCocoa)
なんかこういうのもあります
Subject 📖
PublishSubject
- きほんの Subject
- 外からイベントを流せる Observable みたいなイメージ
-
Observerを配列で持っている -
PublishSubject#subscribe(observer)で渡されたobserverを配列に加える -
PublishSubject#on(event)が呼ばれると抱えているObserver達のonにイベントを渡す -
subscribeもonもあるのでObserverTypeでありObservableTypeでもある
ReplaySubject
-
subscribe(observer)した時に新たに加わったobserverにこれまでのイベントを全て流し直す
BehaviorSubject
-
ReplaySubjectが全てのイベントを流し直すのに対し、最後のイベントだけ流し直すやつ
Variable
-
BehaviorSubjectをラップしてvalueプロパティを生やしたやつ -
Variable.valueを介して値を get / set できる
AsyncSubject
-
on(.completed)が呼ばれたら最後に流れたon(.next(value))イベントのみObserver
に流すやつ
Signal (RxCocoa)
- Error と Complete が流れない Subject
-
RxSwift 4 の Signal と Relay - Qiita
RxTest
TestScheduler
仮想時間を持ってて start を呼ぶとガッと時間を進めてくれる
TestableObservable
-
TestSchadulerを受け取ってインスタンス化 - 仮想時間
tになったらイベントeが流れるという情報 (Recorded) の配列を内部に持っていて、scheduler の仮想時間を進めるとイベントを流してくれる
TestableObserver
-
TestSchadulerを受け取ってインスタンス化 - 仮想時間を進めてイベントが流れてきたら時間とともにイベントを
Recordedに詰めて配列に記録してくれる