호댕의 iOS 개발

[RxSwift] 버튼을 누르는 이벤트를 일정 시간 동안 한 번만 보내고 싶다면 (Throttle, Debounce) 본문

Software Engineering/iOS

[RxSwift] 버튼을 누르는 이벤트를 일정 시간 동안 한 번만 보내고 싶다면 (Throttle, Debounce)

호르댕댕댕 2022. 11. 7. 18:29

개발을 하다가 버튼을 누르는 이벤트를 일정 시간 동안 여러 번 누르더라도 한 번만 인식이 되도록 하고 싶었다. 

버튼을 누르면 view를 띄웠는데 버튼을 여러 번 반복해서 누르는 경우 view가 왕창 떴기 때문이다. 

 

이전에 쓰로틀링(Throttling)을 어디선가 봤기 때문에 Rx에서도 분명 해당 Operator가 있을거란 생각이 들었다. 

 

일단 쓰로틀링이란 단어는 테크 유튜브나 이런 것들을 봤다면 뭔지는 몰라도 어디선가 들어본 사람들이 있을 것이다. 

사전적 정의를 살펴보면 다음과 같다. 

 

성능을 위한 오버클럭(overclock)이 디바이스에 무리를 주는 것을 방지하기 위해 고의로 성능을 낮추는 조절 방식

물론 하드웨어적으로 클럭과 전압을 강제로 낮추거나 전원을 끄는 방식으로 발열을 줄이는 등에도 사용이 가능하지만 이는 소프트웨어적으로도 사용이 가능하다. 

 

또한 Rx에서도 쓰로틀링을 위한 오퍼레이터가 존재한다. 

throttle 

button.rx.tap
    .throttle(.seconds(3), latest: false, scheduler: MainScheduler.instance)

이렇게 하면 3초 동안 아무리 많은 이벤트가 발생하더라도 설정한 만큼 탭 이벤트를 처리하게 된다.

 

그럼 여기서 latest를 true로 줄 때와 false로 줄 때에는 무슨 차이가 있을까?

false로 준 경우

만약 latest 파라미터를 false로 준 경우 마지막 이벤트를 따로 반환하지 않고 3초 동안 1개의 이벤트만 보내게 된다. 아무리 많은 이벤트를 보내도 말이다. 

 

만약 A / B / C / D 이벤트를 3초 동안 보냈다고 하더라도 A 이벤트만 실행되는 것이다. 

 

true로 준 경우 

그렇다면 true로 준 경우는 어떻게 될까? 이때도 처음 A 이벤트는 보내지고 마지막 D 이벤트도 보내지게 된다. 

다만 A 이벤트는 이벤트가 눌린 시점에 바로 보내지지만 D이벤트의 경우 정해진 시간이 됐을 때 보내지게 된다. 

 

 

debounce

비슷한 개념으로 debounce도 존재한다. 

일정 시간 동안 특정 이벤트만 보내는 것은 throttle과 동일하지만 어떤 이벤트를 보내주는지가 다르다. 

 

throttle은 이벤트를 특정 시간동안 필터링해서 보여주지 않는 개념이라면 debounce는 이벤트를 특정 시간 동안 묶어서 마지막 이벤트만 보여주게 된다. 

button.rx.tap
    .debounce(.seconds(3), scheduler: MainScheduler.instance)

만약 이렇게 작성한다면 3초 동안 발생했던 이벤트 중 마지막 이벤트만 보내주게 되는 것이다. 

 

위에 그림을 통해 보자면 3초가 되는 동안 A / B / C / D 이벤트가 발생했더라도 마지막 D 이벤트만 보내주는 것이다. 

ReactiveX의 마블 그림에는 위처럼 나와있다. 

즉, 일정 시간동안에서 마지막에 발생한 이벤트만 보내주는 것이다. 

 

 


다만 debounce의 경우 버튼 이벤트에 사용하기에는 버튼이 눌리고 일정 시간이 지난 후에 반응을 해서 UX적으로 어색하다는 생각이 들었다. 

그래서 이번 경우에는 throttle을 사용해 문제를 해결했다. 

 

 

참고자료

- https://reactivex.io/documentation/operators/debounce.html

 

ReactiveX - Debounce operator

The first variant — called either debounce or throttleWithTimeout — accepts as its parameter a duration, defined as an integer number of milliseconds, and it suppresses any emitted items that are followed by other emitted items during that duration sin

reactivex.io

 

Comments