iPhone: Speeding up a search that's polling 17,000 Core Data objects

Posted by randombits on Stack Overflow See other posts from Stack Overflow or by randombits
Published on 2010-05-03T14:44:32Z Indexed on 2010/05/03 14:48 UTC
Read the original article Hit count: 394

Filed under:
|
|

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.

© Stack Overflow or respective owner

Related posts about iphone

Related posts about core-data