Learn to give your method calls some space to breathe between execution
What is Debouncing a Method Call?
Debouncing a method call ensures that the method is not executed too frequently.
For example: if you see a basic implementation of a search view in any application it does not make an HTTP call to the back end for every character you type. This would result in many HTTP calls and most of them would be unnecessary.
Instead, we use something called a Debouncer
, which calls a particular method only after a given interval of time. For the search example, if we have a time limit of 0.3 seconds then the HTTP call to get the search results will be made when the user has not typed anything for 0.3 seconds. If the user continues to type without pausing for 0.3 seconds the time interval is renewed every time a key is pressed.
Implementing a Custom Debouncer
public class Debouncer {
private let timeInterval: TimeInterval
private var timer: Timer?
typealias Handler = () -> Void
var handler: Handler?
init(timeInterval: TimeInterval) {
self.timeInterval = timeInterval
}
public func renewInterval() {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: false, block: { [weak self] (timer) in
self?.timeIntervalDidFinish(for: timer)
})
}
@objc private func timeIntervalDidFinish(for timer: Timer) {
guard timer.isValid else {
return
}
handler?()
handler = nil
}
}
Let's understand how this has been implemented!
Line 3
: This is the time interval of the debouncer. If no action has been taken for this time interval then the method will be called
Line 4
: We are using a timer to make sure method is not called before the time interval is finished
Line 6,7
: This is a handler closure which will be called when the time interval has ended. Inside this closure, we can implement the code to run, or the code to be debounced.
Line 9
: This is a custom init which takes time interval as parameter. We cannot have a debouncer instance without a time interval
Line 13
: The renew interval method is used to renewal the debounce time interval. If the user is pressing ten keys without pausing the interval will be renewed ten times to ensure we’re checking for time interval from the last user action. Every time this method is called we’re creating a new Timer
which will call a function after time interval is finished.
Line 20
: This method is called when the Timer
completes the time interval. In return, we will call the handler
which is responsible for executing the debounce code.
Using the Debouncer
class ViewController: UIViewController {
let debouncer = Debouncer(timeInterval: 0.3)
override func viewDidLoad() {
super.viewDidLoad()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.doSomething()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.doSomething()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.doSomething()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
self.doSomething()
}
}
}
}
}
func doSomething() {
debouncer.renewInterval()
print("renew interval")
debouncer.handler = {
print("method executed")
}
}
}
Line 3
: We’ve created an instance of Debouncer
with a time interval of 0.3 seconds
.
Line 25
: doSomething
is the method that we are planning to debounce. Every time interval is renewed it will print out renew interval
and whenever the method is executed inside the handler it will print out method executed
.
Line 5
: We are enacting user actions in viewDidLoad
using DispatchQueue
We call the doSomething()
method three times after an interval of 0.1 seconds
. The time interval is greater than 0.1 seconds
so handler will not be executed instead debouncer will renew its interval three times.
Then, there is a pause of 0.4 seconds
— greater than debouncer time interval so it will execute the handler. After that, Line 18
renews the interval once again and execute the handler after 0.3 seconds
.
The output will look like this:
Wrapping Up
This was a basic implementation of Debouncer
. There are many different methods to implement the same thing — they’re all correct if they meet your requirements.
You can find the sample project on Github.