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.
Here's an option for those not wanting to create classes/extensions:
Somewhere in your code:
And in places you want to do the debounce:
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
findPlaces() will only get called one time, 0.25 seconds after the last call to asyncDuped.
Put this at the top level of your file so as not to confuse yourself with Swift's funny parameter name rules. Notice that I've deleted the
#
so that now none of the parameters have names:Now, in your actual class, your code will look like this:
Now
debouncedFindPlaces
is a function which you can call, and yourfindPlaces
won't be executed unlessdelay
has passed since the last time you called it.I used this good old Objective-C inspired method:
Note that the called method
updateSearch
must be marked @objc !The big advantage of this method is that I can pass parameters (here: the search string). With most of Debouncers presented here, that is not the case ...
First, create a Debouncer generic class:
Then create a subclass of UISearchBar that uses the debounce mechanism:
Note that this class is set as the UISearchBarDelegate. Actions will be passed to this class as closures.
Finally, you can use it like so:
Note that in that case, the DebounceSearchBar is already the searchBar delegate. You should NOT set this UIViewController subclass as the searchBar delegate! Nor use delegate functions. Use the provided closures instead!