Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to throttle search (based on typing speed) in iOS UISearchBar?

I have a UISearchBar part of a UISearchDisplayController that is used to display search results from both local CoreData and remote API. What I want to achieve is the "delaying" of the search on the remote API. Currently, for each character typed by the user, a request is sent. But if the user types particularly fast, it does not make sense to send many requests: it would help to wait until he has stopped typing. Is there a way to achieve that?

Reading the documentation suggests to wait until the users explicitly taps on search, but I don't find it ideal in my case.

Performance issues. If search operations can be carried out very rapidly, it is possible to update the search results as the user is typing by implementing the searchBar:textDidChange: method on the delegate object. However, if a search operation takes more time, you should wait until the user taps the Search button before beginning the search in the searchBarSearchButtonClicked: method. Always perform search operations a background thread to avoid blocking the main thread. This keeps your app responsive to the user while the search is running and provides a better user experience.

Sending many requests to the API is not a problem of local performance but only of avoiding too high request rate on the remote server.

Thanks

like image 317
maggix Avatar asked Jun 20 '14 14:06

maggix


1 Answers

Try this magic:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{     // to limit network activity, reload half a second after last key press.     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(reload) object:nil];     [self performSelector:@selector(reload) withObject:nil afterDelay:0.5]; } 

Swift version:

 func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {     // to limit network activity, reload half a second after last key press.       NSObject.cancelPreviousPerformRequestsWithTarget(self, selector: "reload", object: nil)       self.performSelector("reload", withObject: nil, afterDelay: 0.5)  } 

Note this example calls a method called reload but you can make it call whatever method you like!

like image 87
malhal Avatar answered Sep 19 '22 02:09

malhal