Reputation: 3931
I have a viewcontroller with a searchView and a tableView and I want the tableView to display results from a websearch based on the text of the searchView (changing as you add more letters to the search).
As I have it now, each time a letter is added it searches properly but the app stalls as it searches so you can't add in a new letter until the last results have returned.
Is there a smarter way to do this so that when a new letter is added the last search is essentially aborted?
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
if(searchText.length>3)
{
[self getWebDataWithQuery:searchBar.text]
[tblResults reloadData];
}
}
Upvotes: 2
Views: 2143
Reputation: 10175
Another way to do it (I did it like this in one of my projects) I create an NSOperations for the search. Every time a character from the search string was changed I checked if the last search query is not equal with the current, if it wasn't then I cancel all the executing operations and after that I create a new operation and start it.
Off course all the requests/data processing is performed in background thread and only when the downloading/parsing/processing is completed the UI is notified.
Upvotes: 0
Reputation: 17364
You can do something similar:
Then, at every digit, update the filtered array using a predicate. This is good if you have a small dataset (you can even split your data in two arrays and permit the search only on a small subset, like the newest, for example)
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText;
{
if (![searchText isEqualToString:@""]) // here you check that the search is not null, if you want add another check to avoid searches when the characters are less than 3
{
// create a predicate. In my case, attivita is a property of the object stored inside the array
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(attivita CONTAINS[cd] %@)", searchText];
self.filteredArray = [[self.arrayOfActivities filteredArrayUsingPredicate:predicate] mutableCopy];
} else {
self.filteredArray = [self.arrayOfActivities mutableCopy]; // I used a mutable copy in this example code
}
// reload section with fade animation
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
}
Upvotes: 0
Reputation: 11073
You could use a call like this in your search results
dispatch_async(dispatch_get_main_queue(), ^{
[self getWebDataWithQuery:searchBar.text]
[tblResults reloadData]
});
Upvotes: 1
Reputation: 6710
Your call to [self getWebDataWithQuery:searchBar.text]
is calling [NSData datawithContentsOfURL:]
. That is a synchronous call. You need to use an asynchronous mechanism to collect your data from the web service. Either use a third party network framework such as AFNetworking or NSULRConnection.
This will allow the user to continue typing and will not block the UI.
Upvotes: 1