#はじめに
前回
今回は、今まで出てきた用語をもう少し深ぼって学習していきたいと思います。
#解説
###Observable(観測可能)
イベントを検知するためのクラス
ストリームと言われたりする
Observable
が通知するイベントは以下のようなものがある。
・onNext
デフォルトのイベントをながす
イベント内に値を格納でき、何度でも呼び出せる
・onError
エラーイベント
一度だけ呼ばれ、その時点で終了
購読を破棄
・onCompleted
完了イベント
一度だけ呼ばれ、その時点で終了
購読を破棄
###ObservableとObserver
Observable: イベント発生元
Observer: イベント処理
です。例えば、この以下のような感じです。
hogeObservable // Observable
.map { $0 * 10 } // Observable
.subscribe(onNext: {
// Observer
})
.disposed(by: disposeBag)
###disposed
購読を良きタイミングで破棄してメモリリークを回避するための仕組み
###SubjectとRelay
イベントの検知に加えてイベント発生もできる便利なクラス
良い使われるもの
流せるイベント | バッファ | |
---|---|---|
PublishSubject | onNext, onError, onComplete | 持たない |
BehaviorSubject | onNext, onError, onComplete | 持つ |
PublishRelay | onNext | 持たない |
BehaviorRelay | onNext | 持つ |
###バッファ
BehaviorSubject/Relayは、subscribe時に1つ過去のイベントを受け取ることができる。
最初にsubcribeするときは、宣言時に設定した初期値を受け取る。
###SubjectとRelay使い分け
・Subject
通信処理やDB処理等のエラーが発生した時にその内容によって処理を分岐させたい
・Relay
UIに値をBindする
###bind
Observable/Observerに対してbindメソッドを使うと指定したものにイベントストリームを接続できる
単方向のデータバインディング
subscribeして値をセットしているだけ
final class HogeViewController: UIViewController {
@IBOutlet private weak var nameTextField: UITextField!
@IBOutlet private weak var nameLabel: UILabel!
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
//bind利用(subscribeして値をセット)
nameTextField.rx.text
.bind(to: nameLabel.rx.text)
.disposed(by: disposeBag)
//subscribe利用
nameTextField.rx.text
.subscribe(onNext: { [weak self] text in
self?.nameLabel.text = text
})
.disposed(by: disposeBag)
}
}
###Operator
Observableから流れてきた値をそのままsubscribe(またはbind)するのではなく、途中で値を加工してsubscribe(bind)をしたいときに使う。
概略 | Operator | 説明 |
---|---|---|
変換 | map | 通常の高階関数と同じ動き |
flatMap | 通常の高階関数と同じ動き | |
reduce | 通常の高階関数と同じ動き | |
scan | reduceに似ていて、途中結果もイベント発行できる | |
debounce | 指定時間イベントが発生しなかったら、最後に流されたイベントをながす | |
絞り込み | filter | 通常の高階関数と同じ動き |
take | 指定時間の間だけイベントを通知してonCompletedする | |
skip | 指定時間の間はイベントを無視する | |
distinct | 重複イベントを除外する | |
組み合わせ | zip | 複数のObservableを組み合わせる(異なる型でも可能) |
merge | 複数のObservableを組み合わせる(異なる型では不可能) | |
combineLatest | 複数のObservableの最新値を組み合わせる(異なる型でも可能) | |
sample | 引数にわたしたObservableのイベントが発生されたら、元のObservableの最新イベントを通知 | |
concat | 複数のObservableのイベントを順番に組み合わせる(異なる型では不可能) |
###map
//nameTextFieldのテキスト文字数を数えてnameLabelのテキストに反映
nameTextField.rx.text
.map { text -> String? in
guard let text = text else { return nil }
return "あと\(text.count)文字"
}
.bind(to: nameLabel.rx.text)
.disposed(by: disposeBag)
//ボタンをタップしたときにnameLabelにユーザーの名前を表示する
let user = User(name: "REON")
showUserNameButton.rx.tap
.map { [weak self] in
return self?.user.name
}
.bind(to: nameLabel.rx.text)
.disposed(by: disposeBag)
###filter
//整数が流れるObservableから偶数のイベントのみに絞り込んでevenObservableに流す
numberSubject
.filter{ $0 * 2 == 0 }
.bind(to: evenSubject)
.disposed(by: disposeBag)
###zip
//複数のAPIにリクエストして同時に反映したい場合に使える
Observable.zip(firstApiObservable, secondApiObservable)
.subscribe(onNext: { (firstApi, secondApi) in
// ...
})
.disposed(by: disposeBag)
#HotとColdなObservable
###HotなObservable
・subscribeされなくても動作する
・複数の箇所でsubscribeした時に全てのObservableで同じイベントが同時に流れる
###ColdなObservable
・subscribeした時に動作する
・単体では意味がない
・複数の箇所でsubscribeしたとき、それぞれのObservableでそれぞれのイベントが流れる
・使い所は非同期通信処理
#おわりに
次回
RxSwift楽しい!