I have Core Data with +2 millions of rows and i want to search for two specific fields: name & phone (for example). I insert scopes for each field in the Search Bar. Everything go fine if I haven't large data set. That's why I want to search in my core data without load all rows in memory before go search controller. Just need a result when my search text length > 3 or when the Search Button Clicked.
...
If have any idea I will appreciated.
Here you have some codes:
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil) {
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Guia" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:50];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
NSArray *sortDescriptors = @[sortDescriptor];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"GuiaCache"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
abort();
}
return _fetchedResultsController;
}
Maybe in this method I need to improve with some Predicate
- (NSFetchRequest *)searchFetchRequest
{
if (_searchFetchRequest != nil) {
return _searchFetchRequest;
}
_searchFetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Guia" inManagedObjectContext:self.managedObjectContext];
[_searchFetchRequest setEntity:entity];
[_searchFetchRequest setFetchBatchSize:50];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[_searchFetchRequest setSortDescriptors:sortDescriptors];
return _searchFetchRequest;
}
Finaly the two functions to search in Core Data
- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
if ([searchText length] > 3)
[self searchForText:searchText scope:_scopeKeyIndex];
}
- (void)searchForText:(NSString *)searchText scope:(NSUInteger)scopeOption
{
if (self.managedObjectContext)
{
NSString *predicateFormat = @"%K BEGINSWITH[cd] %@";
NSString *searchAttribute = @"telephone";
if (scopeOption == 1)
{
searchAttribute = @"name";
}
NSPredicate *predicate = [NSPredicate predicateWithFormat:predicateFormat, searchAttribute, searchText];
[self.searchFetchRequest setPredicate:predicate];
NSError *error = nil;
_filteredList = [self.managedObjectContext executeFetchRequest:self.searchFetchRequest error:&error];
}
}
If you need some other piece of code, just comment.
First, run Instruments against your application, specifically Time Profiler. Where does it say the time is being spent?
Do you have a predicate in your search? What does the predicate look like? You need to show some code for people to help.
Doing a fetch against against 2 million records will take a bit of time but I suspect it is not loading 2 million rows into memory as that would most likely cause memory problems as well as speed problems.
Post the results from Time Profiler and lets see where the time is being spent.
First your predicate is very expensive. BEGINSWITH
should be avoided if at all possible. Making it both case and diacritic insensitive increases that cost dramatically.
Did you run Instruments against your code? Did you run the time profiler? Without running that you are just guessing. You NEED to run the time profiler and at least show the results if not link to the entire profile.