# Swift에서 Debounce vs Throttle 차이점 (UIKit 예제)
안녕하세요 __물먹고하자__ 입니다 :)
지난번에 검색영역의 API를 붙이던중 __잦은 네트워크 중복방지__를 위해
__Debounce__를 적용했던점이 있는데, 내용을 찾아보니
__Debounce vs Throttle__ 해당내용이 많이 있더군요.
샘플링을 하면서 내용한번 정리해보려고 합니다.
---
## #.샘플링
> 💡 업무를 진행하던중 검색부분이 로컬 > API로 변경이되면서 __샘플링되었던 화면__
타이핑은 쭉 진행이되고, 0.5초기준점 들어왔던 __마지막 검색(Text)만 API 요청__

---
## 1. Debounce
> *__마지막 입력만 처리__ (이것 때문에 사용하죠)
*사용자가 입력을 멈춘 뒤 설정한 시간(ms) 이후에 __최신 이벤트를 전달__
*주로 __검색 API 호출__ 같은 곳에서 사용
💡 예시상황
*사용자가 __h, he, hel, hell, hello 입력__
*0.5초 동안 아무 입력이 없을 때 → __"hello" 로 API 호출 1번 발생__

---
## 2. Throttle
> *주기마다 가장 첫 입력 or 마지막 입력만 처리
*사용자가 입력을 빠르게 하더라도 설정한 주기마다 1번만 이벤트 전달
*주로 버튼 중복 클릭 방지, 위치 업데이트 등에 사용
💡 예시상황
*사용자가 h, he, hel, hell, hello 입력 (0.1초 간격)
*0.5초 throttle 적용 시 → "h", "he", "hel"… 중에서 일정 주기마다 1번씩 API 호출 발생

---
## 3.샘플코드 부분
> 💡 __Debounce, Throttle__ 성향은 다르지만, 저의경우는 거의 __Debounce__ 하나만으로도 충분했던것 같습니다.
Debounce : 실시간검색시 일정 딜레이(이때가 제일 많이 활용)
Throttle : 버튼 액션에서 연달아 누르는 행위를 막을때
아래 샘플 코드로 직접 실행해 보시면 도움될 것 같습니다.
```swift
import UIKit
import Combine
class ViewController: UIViewController {
private let textField = UITextField() // 검색어 영역
private let resultLable = UILabel() // 결과부분
private var cancellables = Set()
private let searchTrigger = PassthroughSubject()
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
// setupDebounce() // debounce 테스트
setupThrottle() // Throttl 테스트
}
private func setupUI() {
textField.borderStyle = .roundedRect
textField.placeholder = "검색어 입력"
textField.addTarget(self, action: #selector(textChanged), for: .editingChanged)
view.backgroundColor = .systemBackground
view.addSubview(textField)
textField.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
textField.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -50),
textField.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
textField.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)
])
resultLable.text = "검색이 될 결과 정보"
view.addSubview(resultLable)
resultLable.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
resultLable.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 50),
resultLable.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 40),
resultLable.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -40)
])
}
@objc private func textChanged() {
searchTrigger.send(textField.text ?? "")
}
// ✅ Debounce: 입력 멈춘 뒤 0.5초 후 마지막 값으로 호출
private func setupDebounce() {
searchTrigger
.debounce(for: .milliseconds(500), scheduler: RunLoop.main)
.sink { text in
print("🔍 API 호출 (Debounce) : \(text)")
self.resultLable.text = text
}
.store(in: &cancellables)
}
// ✅ Throttle: 0.5초마다 1번만 호출
private func setupThrottle() {
searchTrigger
.throttle(for: .milliseconds(500), scheduler: RunLoop.main, latest: true)
.sink { text in
print("🔍 API 호출 (Throttle) : \(text)")
self.resultLable.text = text
}
.store(in: &cancellables)
}
}
```
---
## 마무리
가끔 어렵게 쓰고 있었던 부분들이 있었는데, 그중에 하나가 Debounce 였던 부분인것 같습니다.
별도로 생각안하고, "Task에 들어오는 값들을 취소하고 마지막걸 실행해야지~"
했던게 아예 Combine에 있었내요.
그래서 공부차원으로 변경했고 내용도 정리했습니다.
오늘은 이만~
즐거운 코딩 되게요.
끝.
댓글
댓글 쓰기