Help us understand the problem. What is going on with this article?

RxSwift/RxCocoa Driver Unitについてまとめてみた。

More than 3 years have passed since last update.

Driver Unitについてまとめてみた

川を引き始めて3ヶ月、ようやくDriverについて少しわかってきたので自身の理解を深めるために一度まとめてみた。

Driver Unitとは

DriverはUIに特化されている!!

Driverの特徴
1.エラーでストリームが終了しない
2.メインスレッドで行われる
3.サイドエフェクトをシェアする(あまりよくわかっていない)

Driver Unitの一番の特徴はエラーが起きない事です!(正確にはエラーを購読して[ ]を返している)。Observableを使っていた場合ErrorCompletedでストリームが終了してしまうが、Driver(asDriver)の場合はエラーが流れてきた場合は適当なものを返して購読を続けてくれます。なのでAPI通信などがエラーだった場合でもストリームが終了する事なく購読が続きます。

Example

Sample
@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を書いてみましょう

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を使って同じ処理を行ってみましょう。

sample2
@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が行う事
1. .observeOn(MainScheduler.instance) メインスレッドで行う
2. .catchErrorJustReturn(onErrorJustReturn) 絶対にエラーで購読が終了しない
3. .shareReplayLatestWhileConnected サイドエフェクトをシェアする(やっぱりあまり理解できていない)

3つめのサイドエフェクトをシェアするに関する事でなにかありましたらコメントをいただけると幸いです。

yuzushioh
20歳です!!
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした