LoginSignup
141
69

More than 5 years have passed since last update.

Swift愛好会 Advent Calendar 2017の12日目担当の @dekatotoroです。

昨日は、 @marty-suzukiさんの 「Swift4からprotocolのassociatedtypeでできるようになったこと」 でした。
今日は「RxSwiftのDebounceとThrottle」についてです。

RxSwiftのoperatorにDebounceThrottleがありますが、
「あれ、どっちがどういう動作だったっけ?」と思ったことはありませんか。
忘れたときはこの記事を見てみてください :smiley:

パターンは3つあります。

  • Debounce
  • Throttle (latest true)
  • Throttle (latest false)

以下のストリームをを例にします。
※ 確認したversionは RxSwift 4.0.0

let observable = Observable<Int>.create { observer in

    observer.onNext(1)
    observer.onNext(2)
    observer.onNext(3)

    sleep(2)

    observer.onNext(4)
    observer.onNext(5)
    observer.onNext(6)

    sleep(2)

    observer.onCompleted()
    return Disposables.create()
    }

stream.png

Debounce

指定期間新たなイベントが発行されなくなってから、最後に発行されたイベントを発行します。途中のイベントは無視されます。

_ = observable
    .debounce(1, scheduler: scheduler) // 3, 6
    .subscribe(onNext: {
        print("debounce: \($0)")
    })

図にしてみます。
debounce.png

Throttle

RxSwift 3.4.0からlatestパラメーターが追加されています。
defaultはtrueです。

計測が開始された最初のイベントと、指定期間内で最後に発行されたイベント(最初のイベント以外)を発行します。途中のイベントは無視します。
latestがfalseの場合は、計測が開始された最初のイベントを発行し、指定期間内のイベントは全て無視します。

debounceとの違いは、指定期間の計測が開始された最初のイベントを発行すること、latestがtrueの場合は指定期間内で発行されたイベント(最初のイベント以外)が指定期間経つと必ず発行するところです。

Throttle (latest true)

_ = observable
    .throttle(1, latest: true, scheduler: scheduler) // 1, 3, 4, 6
    .subscribe(onNext: {
        print("throttle true: \($0)")
    })

図にしてみます。
throttle_true.png

Throttle (latest false)

_ = observable
    .throttle(1, latest: false, scheduler: scheduler) // 1, 4
    .subscribe(onNext: {
        print("throttle false: \($0)")
    })

図にしてみます。
throttle_false.png

Example

実際に使用する例です。
debounceはインクリメンタルサーチなどでAPIを叩き過ぎないようにするのに便利ではないでしょうか。
throttle latest falseはボタン連打防止など色々用途がありそうです。
throttle latest trueはあまり使い所が思い浮かばないなので、使ってる方は使用例ご教授ください :pray:


class ViewController: UIViewController {

    @IBOutlet private weak var searchBar: UISearchBar!
    @IBOutlet private weak var button: UIButton!
    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        searchBar.rx.text
            .debounce(0.3, scheduler: MainScheduler.instance)
            .subscribe(onNext: { text in
                print("UISearchBar debounce: \(text ?? "") \(Date())")
            })
            .disposed(by: disposeBag)

        button.rx.tap.asObservable()
            .throttle(1.0, latest: false, scheduler: MainScheduler.instance)
            .subscribe(onNext: { _ in
                print("UIButton throttle latest false: \(Date())")
            })
            .disposed(by: disposeBag)
    }
}

以上になります :smile:

Swift愛好会 Advent Calendar 2017 明日は @mizukoA になります!

141
69
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
141
69