I'm trying to use a UISearchView
to query google places. In doing so, on text change calls for my UISearchBar
, I'm making a request to google places. The problem is I'd rather debounce this call to only request once per 250 ms in order to avoid unnecessary network traffic. I'd rather not write this functionality myself, but I will if I need to.
I found: https://gist.github.com/ShamylZakariya/54ee03228d955f458389 , but I'm not quite sure how to use it:
func debounce( delay:NSTimeInterval, #queue:dispatch_queue_t, action: (()->()) ) -> ()->() { var lastFireTime:dispatch_time_t = 0 let dispatchDelay = Int64(delay * Double(NSEC_PER_SEC)) return { lastFireTime = dispatch_time(DISPATCH_TIME_NOW,0) dispatch_after( dispatch_time( DISPATCH_TIME_NOW, dispatchDelay ), queue) { let now = dispatch_time(DISPATCH_TIME_NOW,0) let when = dispatch_time(lastFireTime, dispatchDelay) if now >= when { action() } } } }
Here is one thing I've tried using the above code:
let searchDebounceInterval: NSTimeInterval = NSTimeInterval(0.25) func findPlaces() { // ... } func searchBar(searchBar: UISearchBar!, textDidChange searchText: String!) { debounce( searchDebounceInterval, dispatch_get_main_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT), self.findPlaces ) }
The resulting error is Cannot invoke function with an argument list of type '(NSTimeInterval, $T5, () -> ())
How do I use this method, or is there a better way to do this in iOS/Swift.
The debounce() function forces a function to wait a certain amount of time before running again. The function is built to limit the number of times a function is called. The Send Request() function is debounced. Requests are sent only after fixed time intervals regardless of how many times the user presses the button.
Debouncing enforces that there is a minimum time gap between two consecutive invocations of a function call. For example, a debounce interval of 500ms means that if 500ms hasn't passed from the previous invocation attempt, we cancel the previous invocation and schedule the next invocation of the function after 500ms.
Here's an option for those not wanting to create classes/extensions:
Somewhere in your code:
var debounce_timer:Timer?
And in places you want to do the debounce:
debounce_timer?.invalidate() debounce_timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { _ in print ("Debounce this...") }
If you like to keep things clean, here's a GCD based solution that can do what you need using familiar GCD based syntax: https://gist.github.com/staminajim/b5e89c6611eef81910502db2a01f1a83
DispatchQueue.main.asyncDeduped(target: self, after: 0.25) { [weak self] in self?.findPlaces() }
findPlaces() will only get called one time, 0.25 seconds after the last call to asyncDuped.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With