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: 439
        
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