Add a UISegmentedController to navigation bar with NSFetchedResultsController
I am working with a UITableView
that gets its data from an NSFetchedResultsController
. I would like to add a UISegmentedControl
to my navigation bar that would toggle the table between displaying all of the records and only the records where starred == YES
.
I have read some other SO posts indicating that one way to do this is to create a second NSFetchedResultsController
that has an NSPredicate
wit开发者_开发问答h starred == YES
, but it seems awfully overkill to create a second NSFetchedResultsController
.
Is there a simpler way to do this?
Not according to the docs on NSFetchedResultsController. If you take a look at the documentation on the fetchRequests property, you'll see the following note:
Important: You must not modify the fetch request. For example, you must not change its predicate or the sort orderings.
Since the fetchRequest property is read-only, the only option is creating a new fetched results controller.
It might be possible to change the predicate and have things work, but it's generally a bad idea to do stuff that goes explicitly against things Apple says in the documentation, because it could break in a future release.
And, beware of premature optimization! Unless you've tested it out and found out that creating a whole new fetched results controller is a big performance drain, it's not worth trying to do something in a non-recommended way.
Here's how I set a new predicate on my fetched results controller. fetchedResultsController is a property of my view controller. predicate is a private ivar of the view controller.
I already had all of the code for creating the fetched results controller on demand, so to set the predicate it's just a matter of deleted the cached one.
- (void)setPredicate:(NSPredicate *)newPredicate {
predicate = [newPredicate copy];
// Make sure to delete the cache
// (using the name from when you created the fetched results controller)
[NSFetchedResultsController deleteCacheWithName:@"Root"];
// Delete the old fetched results controller
self.fetchedResultsController = nil;
// TODO: Handle error!
// This will cause the fetched results controller to be created
// with the new predicate
[self.fetchedResultsController performFetch:nil];
[self.tableView reloadData];
}
This code if based on the boilerplate XCode generates when you start a project that uses Core Data.
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil) {
return fetchedResultsController;
}
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:[MyEntity entityName] inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[fetchRequest setPredicate:predicate];
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
return fetchedResultsController;
}
精彩评论