Driver Unitについてまとめてみた
川を引き始めて3ヶ月、ようやくDriverについて少しわかってきたので自身の理解を深めるために一度まとめてみた。
Driver Unitとは
DriverはUIに特化されている!!
Driverの特徴
1.エラーでストリームが終了しない
2.メインスレッドで行われる
3.サイドエフェクトをシェアする(あまりよくわかっていない)
Driver Unitの一番の特徴はエラーが起きない事です!(正確にはエラーを購読して[ ]を返している)。Observable
を使っていた場合Error
かCompleted
でストリームが終了してしまうが、Driver
(asDriver
)の場合はエラーが流れてきた場合は適当なものを返して購読を続けてくれます。なのでAPI通信などがエラーだった場合でもストリームが終了する事なく購読が続きます。
#Example
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var resultLabel: UILabel!
let result = textField.rx_text
.flatMapLatest { text in
//API通信
}
result
.map { $0.description }
.bindTo(resultLabel.rx_text)
.addDisposableTo(disposeBag)
result
.bindTo(tableView..rx_itemsWithCellIdentifier("Cell")) { _, result, cell in
cell.textLabel?.text = "\(result.totalCount)"
}
.addDisposableTo(disposeBag)
上記のサンプルだとflatMapLatest
内でエラーが起こったらストリームが終了してしまいresult
が更新されてもUIは更新されません。そしてAPI通信がメインスレッド以外で行なわれているとクラッシュの原因にもなります!
そして上記の場合だと1つのストリームを二つのUIにバインドしているので2回HTTPリクエストが送られています。
ではこれらの問題をふまえてsample2
を書いてみましょう
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var resultLabel: UILabel!
let result = textField.rx_text
.flatMapLatest { text in
//API通信
.observeOn(MainScheduler.instance)
.catchErrorJustReturn([])
}
.shareReplay(1)
result
.map { $0.description }
.bindTo(resultLabel.rx_text)
.addDisposableTo(disposeBag)
result
.bindTo(tableView..rx_itemsWithCellIdentifier("Cell")) { _, result, cell in
cell.textLabel?.text = "\(result.totalCount)"
}
.addDisposableTo(disposeBag)
.observeOn(MainScheduler.instance)
を使う事でメインスレッドで行う事を保証し、エラーの時には.catchErrorJustReturn([])
を使って[]
をreturn
します。catchError { _ in Observable.empty() }
でもエラーで購読を終了しないようにエラー処理ができる。
1回のリクエストの結果を2つのUIにシェアするためにここでは.shareReplay(1)
を使って処理をしています。
では最後にDriverを使って同じ処理を行ってみましょう。
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var resultLabel: UILabel!
let result = textField.rx_text.asDriver
.flatMapLatest { text in
//API通信
.asDriver(onErrorJustReturn: [])
}
result
.map { $0.description }
.Drive(resultLabel.rx_text)
.addDisposableTo(disposeBag)
result
.Drive(tableView..rx_itemsWithCellIdentifier("Cell")) { _, result, cell in
cell.textLabel?.text = "\(result.totalCount)"
}
.addDisposableTo(disposeBag)
#まとめ
Driverが行う事
-
.observeOn(MainScheduler.instance)
メインスレッドで行う -
.catchErrorJustReturn(onErrorJustReturn)
絶対にエラーで購読が終了しない -
.shareReplayLatestWhileConnected
サイドエフェクトをシェアする(やっぱりあまり理解できていない)
3つめのサイドエフェクトをシェアするに関する事でなにかありましたらコメントをいただけると幸いです。