스터디에서 한 분이 debounce 관련된 질문을 받으셨다고 하셔서 궁금해 찾아보았고 참고하여 button에 적용시켜봤다.
생각보다 간단했는데 서브클래싱, 클로저 그리고 task를 캡슐화 할 수 있는DispatchWorkItem을 사용해서 구현하면 비슷하게 작동한다
class DebounceButton: UIButton {
deinit {
self.removeTarget(self, action: #selector(self.editingChanged(_:)), for: .touchUpInside)
}
private var workItem: DispatchWorkItem?
private var delay: Double = 0
private var callback: ((Date) -> Void)? = nil
func debounce(delay: Double, callback: @escaping ((Date) -> Void)) {
self.delay = delay
self.callback = callback
self.addTarget(self, action: #selector(self.editingChanged(_:)), for: .touchUpInside)
}
@objc private func editingChanged(_ sender: UIButton) {
self.workItem?.cancel()
let workItem = DispatchWorkItem(block: { [weak self] in
self?.callback?(Date())
})
self.workItem = workItem
DispatchQueue.main.asyncAfter(deadline: .now() + self.delay, execute: workItem)
}
}
class ThrottleButton: UIButton {
deinit {
self.removeTarget(self, action: #selector(self.editingChanged(_:)), for: .touchUpInside)
}
private var workItem: DispatchWorkItem?
private var delay: Double = 0
private var callback: ((Date) -> Void)? = nil
func throttle(delay: Double, callback: @escaping ((Date) -> Void)) {
self.delay = delay
self.callback = callback
self.addTarget(self, action: #selector(self.editingChanged(_:)), for: .touchUpInside)
}
@objc private func editingChanged(_ sender: UIButton) {
if self.workItem == nil {
self.callback?(Date())
let workItem = DispatchWorkItem(block: { [weak self] in
self?.workItem?.cancel()
self?.workItem = nil
})
self.workItem = workItem
DispatchQueue.main.asyncAfter(deadline: .now() + self.delay, execute: workItem)
}
}
}
https://docfriends.github.io/DevStrory/2019-01-29/swift-delay/