NSFetchedResultsController fetch request - updating predicate and UITableView
In my iPhone Core Data app I have it configured in a master-detail view setup.
The master view is a UITableView that lists objects of the List
entity. The List entity has a to-many relationship with the Task
entity (called "tasks"), and the Task entity has an inverse to-one relationship with List
called "list".
When a List
object is selected in the master view, I want the detail view (another UITableView) to list the Task
objects that correspond to that List
object. What I've done so far is this:
In the detail view controller I've declared a property for a List
object:
@property (nonatomic, retain) List *list;
Then in the master view controller I use this table view delegate method to set the list
property of the detail view controller when a list is selected:
- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
detailViewController.list = (List*)selectedObject;
}
Then, I've overriden the setter for the list
property in the detail view controller like this:
- (void)setList:(List*)newList
{
if (list != newList) {
[list release];
list = [newList retain];
NSPredicate *newPredicate = [NSPredicate predicateWithFormat:@"(list == %@)", list];
[NSFetchedResultsController deleteCacheWithName:@"Root"];
[[[self fetchedResultsController] fetchRequest] setPredicate:newPredicate];
NSError *error = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
What I'm doing here is setting a predicate on the fetched results to filter out the objects so that I only get the ones that belong to the selected List
object. The fetchedResultsController getter for the detail view controller looks like this:
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController == nil) {
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Task" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"FALSEPREDICATE"];
[fetchRequest setPredicate:predicate];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
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;
}
Its almost unchanged from the default in the Core Data project template, the change I made is to add a predicate that always returns false, the reason being that when there is no List selected I don't want any items to be displayed in the detail view (if a list is selected the predicate is changed in the setter for the list property).
However, when I select a list item, nothing really happens. No开发者_JAVA百科thing in the table view changes, it stays empty. I'm sure my logic is flawed in several places, advice is appreciated
Thanks
You don't need to set up a NSFetchedResultsController
for your task list. Since you are passing in the List entity, you can just ask the List entity for the tasks:
NSSet *tasks = [[self list] valueForKey:@"tasks"];
NSSortDescriptor *sort = ...;
NSArray *sorted = [[tasks allObjects] sortedArrayUsingDescriptors:[NSArray arrayWithObject:sort]];
[self setTasks:sorted];
Then have the UITableviewDatasource
methods run off of that tasks
array.
Maybe I don't understand your setup completely, but
detailViewController.list.task
(or whatever that relationship is called) will return an NSSet of any Task objects that are associated with the List object.
Well, I have a similar issue, and I posted my question at How to switch UITableView's NSFetchedResultsController (or its predicate) programmatically?.
After I posted it, I decided to try out your code. And you know what? It works, with only a small addition:
[self.tableView reloadData];
Perhaps you can go back to your initial code and confirm.
Regards.
精彩评论