iPhone: Speeding up a search that's polling 17,000 Core Data objects
- by randombits
I have a class that conforms to UISearchDisplayDelegate and contains a UISearchBar. This view is responsible for allowing the user to poll a store of about 17,000 objects that are currently managed by Core Data. Everytime the user types in a character, I created an instance of a SearchOperation (subclasses NSOperation) that queries Core Data to find results that might match the search. The code in the search controller looks something like:
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
// Update the filtered array based on the search text and scope in a secondary thread
if ([searchText length] < 3) {
[filteredList removeAllObjects]; // First clear the filtered array.
[self setFilteredList:NULL];
[self.tableView reloadData];
return;
}
NSDictionary *searchdict = [NSDictionary dictionaryWithObjectsAndKeys:scope, @"scope", searchText, @"searchText", nil];
[aSearchQueue cancelAllOperations];
SearchOperation *searchOp = [[SearchOperation alloc] initWithDelegate:self dataDict:searchdict];
[aSearchQueue addOperation:searchOp];
}
And my search is rather straight forward. SearchOperation is a subclass of NSOperation. I overwrote the main method with the following code:
- (void)main
{
if ([self isCancelled]) {
return;
}
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSEntityDescription *entity =
[NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSPredicate *predicate = NULL;
predicate = [NSPredicate predicateWithFormat:@"(someattr contains[cd] %@)", searchText];
[fetchRequest setPredicate:predicate];
NSError *error = NULL;
NSArray *fetchResults = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
[fetchRequest release];
if (self.delegate != nil)
[self.delegate didFinishSearching:fetchResults];
[pool drain];
}
This code works, but it has several issues.
It's slow. Even though I have the search happening in a separate thread other than the UI thread, querying 17,000 objects is clearly not optimal.
If I'm not careful, crashes can happen. I set the max concurrent searches in my NSOperationQueue to 1 to avoid this.
What else can I do to make this search faster? I think preloading all 17,000 objects into memory might be risky. There has to be a smarter way to conduct this search to give results back to the user faster.