My app has a UISearchBar allowing user to enter search keywords. Each keystroke executes a Core Data query in order to display the results as text in search bar changes.
The problem is that search bar keystrokes are lagging pretty bad... surely because of slow fetching. Any ideas how to improve the performance?
My Core Data is backed with sqlite data store which contains 1000 objects.
// searchKeyword is the string appears in UISearchBar
// Both title and author may contain several words so I can't use BEGINSWITH
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"(author CONTAINS[c] %@) OR (title CONTAINS[c] %@)", searchKeyword, searchKeyword];
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:managedObjectContext];
NSFetchRequest* request = [[NSFetchRequest alloc] init];
[request setEntity:entity];
[request setPredicate:predicate];
[request setFetchLimit:10];
NSSortDescriptor* sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"title" ascending:YES];
NSArray* sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptor release];
[sortDescriptors release];
execute request and fetch the results
fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:managedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
NSError* error = nil;
BOOL success = [fetchedResultsController performFetch:&error];
[request release];
Core Data is incredibly fast if you consider what it does under the hood to do its magic. But Realm is faster, much faster. Realm was built with performance in mind and that shows. As Marcus Zarra once said in a presentation, you don't choose Core Data for its speed.
Core Data is a framework that you use to manage the model layer objects in your application. It provides generalized and automated solutions to common tasks associated with object life cycle and object graph management, including persistence.
Using CONTAINS slows it down. What you need to do is create a new table called searchWords (or whatever), and in that store all the words within your titles, made lower case and with accents removed. These have a relationship linking them back to the original objects. Make sure the word field is indexed.
Perform your query on this table, but instead of using CONTAINS or BEGINSWITH, do something like
word > "term" AND word < "tern"
Note that the first string in there is the search term, and the second is the search term with the last character incremented. This allows Core Data to use the SQL index to perform the search.
Apple have a Core Data WWDC session that explains this, including sample code. The sample code contains a class that handles normalising the string (I.e. Removing case), and incrementing the last character of a word in a unicode aware way.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With