Getting NSFetchedResultsController, NSSortDescription and sectionNameForKeyPath for collaboration

I am currently working on an application that has a couple of entities and relationships, as shown below:

Element ↔ Category .

I am currently retrieving instances of Item and displaying them in sections using the category.name element. In this case, I can use the sort descriptor to sort the categories by name, which is quite simple and works fine (corresponding 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_; } 

Now my problem is that I need to sort these categories not by name, but by using the (NSNumber*) displayOrder , which is part of the Category object. BUT I need section headings in the table to continue using the name category.

If I set sortDescriptor to use category.displayOrder and save sectionNameKeyPath as category.name , the section headers work fine, but the sortDescriptor is simply ignored by the fetchedResultsController and the table sections are sorted by category name (not sure why ??).

My next idea was to overwrite the displayOrder getter method, but that didn't get me too far, since the return types are different from each other, plus I needed the actual displayOrder value to sort the section.

So right now, I have a solution that seems a bit awkward (the code below), and I'm wondering if there is a better way to achieve the same thing using only fetchedResultsController.

 - (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]; } 

Did I miss something basic here?

Thanks in advance for your thoughts.

Horn

+7
source share
4 answers

This is the perfect solution, Rog.

You certainly do not want / need a subclass of NSFetchedResultsController.

@aroth, we don’t have enough information to know the details of his object model, but the names certainly imply that the category does not own the element . The item has a category. His intention is to display a list of elements, so he retrieves the elements.

+1
source

As for sorting, in the documentation , this can be said:

If the controller generates partitions, the first sort descriptor in the array is used to group objects into partitions; its key must either be the same as sectionNameKeyPath, or the relative order using its key must match using sectionNameKeyPath.

In English (perhaps you already know this Horn, but again you cannot and, of course, people who look for it later can appreciate the explanation), this means that if you use sections, sorting by NSFetchRequest should group all the elements in the same section together. This may be due to the fact that the first sorting criterion is the field used as the section name, or it may be due to the fact that the first sorting criterion is something else, which leads to the same grouping.

The documentation does not indicate what will happen if you ruin it; perhaps it will just completely ruin the partition names, repeat the partitions, skip the partitions, detect a situation and β€œfix” your sort or even just crash. Do any of your categories have the same displayOrder?

Your solution, of course, is workable, and if you cannot get it to work correctly by sorting displayOrder, and section headings by .name categories are probably your best solution.

+1
source

Why do you choose Item rather than Category ? If I understand your relationship correctly, Category has a relationship from 1 to many with Item , so theoretically an instance of Category should have a "items" property that returns every Item in this category.

If that happens, you can just get all your categories and then sort them by displayOrder . Then forget about using partitions in NSFetchedResultsController . Instead, your related tableView methods look something like this:

 - (NSInteger)numberOfSections { return [[self.fetchedResultsController fetchedObjects] count]; } - (NSInteger)numberOfRowsInSection:(NSInteger)section { Category* category = [[self.fetchedResultsController fetchedObjects] objectAtIndex:section]; return [[category items] count]; } - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { Category* category = [[self.fetchedResultsController fetchedObjects] objectAtIndex:section]; return category.name; } 

In short, I think you're excessive by adding Item instead of Category , and trying to make NSFetchedResultsController control your sectional grouping for you. It is much simpler and requires much less code to just manage partitions.

+1
source

You probably need to subclass NSFetchedResultsController and configure section name functions. See Documents of the NSFetchedResultsController Class for a Subclass.

0
source

All Articles