RxSwiftのDebounceとThrottle

[Swift愛好会 Advent Calendar 2017](https://qiita.com/advent-calendar/2017/love_swift)の12日目担当の @dekatotoroです。

昨日は、 @marty-suzukiさんの [「Swift4からprotocolのassociatedtypeでできるようになったこと」](https://qiita.com/marty-suzuki/items/8a7e4fa296e4a861057f) でした。
今日は**「RxSwiftのDebounceとThrottle」**についてです。

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

パターンは３つあります。
-
- Debounce
- Throttle (latest true)
- Throttle (latest false)


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

```swift
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](https://qiita-image-store.s3.amazonaws.com/0/48971/3ba88748-e12c-d788-d2ff-f7ac3353b060.png)

# **Debounce**

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

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

図にしてみます。
![debounce.png](https://qiita-image-store.s3.amazonaws.com/0/48971/3b40471b-b6c3-6658-b9e1-c5ec011d3350.png)




# **Throttle**
[RxSwift 3.4.0](https://github.com/ReactiveX/RxSwift/releases/tag/3.4.0)からlatestパラメーターが追加されています。
defaultは**true**です。

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

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


## **Throttle (latest true)**

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

図にしてみます。
![throttle_true.png](https://qiita-image-store.s3.amazonaws.com/0/48971/4fd150d9-04c0-ae91-00f7-2d887b7adeb7.png)



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

図にしてみます。
![throttle_false.png](https://qiita-image-store.s3.amazonaws.com/0/48971/1a0406b1-1f32-e136-a357-adb8a6317e2e.png)


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

```swift

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](https://qiita.com/advent-calendar/2017/love_swift) 明日は @mizukoA になります！