I'm currently working on an App that has a couple of Entities and relationships as illustrated below:
Item <<--> Category.
I am currently fetching Item instances and displaying them in sections using the item's category.name
. In this case I can use a sort descriptor to sort the categories by name, which is pretty straightforward and working fine (relevant code below):
-(NSFetchedResultsController*)fetchedResultsController {
if (fetchedResultsController_ != nil)
return fetchedResultsController_;
NSManagedObjectContext *moc = [order_ managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Item" inManagedObjectContext:moc];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"category.name" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSFetchedResultsController *controller = [[NSFetchedResultsController alloc]
initWithFetchRequest:fetchRequest
managedObjectContext:moc
sectionNameKeyPath:@"category.name"
cacheName:nil];
controller.delegate = self;
self.fetchedResultsController = controller;
[controller release];
[fetchRequest release];
NSError *error = nil;
if (![fetchedResultsController_ performFetch:&error]) {
// Error handling
}
return fetchedResultsController_;
}
My problem now is that I need to sort these categories not by name, but by a (NSNumber*) displayOrder
attribute that is part of the Category entity. BUT I need the section titles on the tableview to continue to use the categorie's name
.
If I set the sortDescriptor to use category.displayOrder
and keep the sectionNameKeyPath as category.name
, the section titles work fine but the sortDescriptor is simply ignored by the fetchedResultsController and the table sections are ordered by the category's name (not sure why??).
My next idea was to overwrite the displayOrder
getter method but that didn't get me too far as the return types are different, plus I needed the actual displayOrder value for the section sorting.
So right now I have a solution which feels a bit clunky (code below), and I am wondering if there is a better way of achieving the same thing using the fetchedResultsController alone.
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
// The code below grabs a reference to first object for a given section
// and uses it to return the associated category name
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
NSArray *menuItems = [sectionInfo objects];
if ([menuItems count] > 0)
{
MenuItem *menuItem = [menuItems objectAtIndex:0];
NSString *categoryName = menuItem.category.name;
return categoryName;
}
return [sectionInfo name];
}
Am I missing something basic here?
Thanks in advance for your thoughts.
Rog
You probably need to subclass NSFetchedResultsController and customize the section name functions. See the NSFetchedResultsController class docs on subclassing.
As far as sorting goes, the documentation has this to say:
In English (you may already know this Rog, but then again you may not and certainly people who search this later may appreciate the explanation), that means if you're using sections then the sorting on the NSFetchRequest must group all items in the same section together. This could be by making the first sort criteria be the field used as the section name, or it could be by making the first sort criteria be something else that results in the same sort of grouping.
The documentation doesn't specify what happens if you screw this up; it's possible it would just totally screw up the section names, repeat sections, skip sections, detect the situation and "fix" your sorting, or even just crash. Do any of your categories have the same displayOrder?
Your solution is certainly workable, and if you can't get it to work correctly sorting by displayOrder while titling sections by category.name it's probably your best solution.
That's a perfectly good solution to the problem, Rog.
You certainly don't want/need to subclass NSFetchedResultsController.
@aroth, we don't have enough information to know the details of his object model, but the names certainly imply that category does not own item. Item has a category. His intent is to display a list of items, that is why he is fetching items.
Why are you fetching
Item
and notCategory
? If I understand your relationships correctly,Category
owns a 1 to many relationship withItem
, so in theory aCategory
instance should have an 'items' property that returns everyItem
in that category.If that's the case, then you could simply fetch all of your categories, and then sort them by
displayOrder
. Then, forget about using sections in theNSFetchedResultsController
itself. Instead, your associatedtableView
methods would look something like:In short, I think you are overcomplicating things by fetching
Item
instead ofCategory
, and by trying to make theNSFetchedResultsController
manage your section grouping for you. It is much simpler and requires much less code to just do the section management yourself.