Core Data: UITableView with multiple NSFetchedResultControllers
Multiple fetch controllers (and possibly multiple entities) is the wrong approach. The correct solution is to use the sectionNameKeyPath
param to the NSFetchedResultController
to group the results into multiple sections. If you think about your entities differently perhaps they are actually the same entity and instead you can use a property itemType
which you can then section on (and you must also sort on it too). E.g. say I had entities Hops and Grains then I could change those to Ingredient and have a int_16 property ingredientType
which I then have an enum in code to store the values hopType = 0
, grainType = 1
. After all the ingredient is just a name and a weight, which both of these share.
If however your entities really have a distinct set of properties, then the correct solution is to create a parent abstract entity that has a property that you can use to section, e.g. sortOrder
, sectionID
or type
. When you then create a fetch controller and fetch the abstract parent entity, you actually get results containing all of the sub-entities. E.g in the Notes app they have an abstract parent entity NoteContainer
that has child entities Account
and Folder
. This enables a single fetch controller to display the account in the first cell in the section, and then have all the folders in the following cells. E.g. All iCloud Notes (is actually the account), then Notes (is the default folder), followed by all the custom folders, then the trash folder. They use a sortOrder
property and the default folder is 1
, the custom folders are all 2
, and the trash is 3
. Then by adding this as a sort descriptor they can have the cells display in the order they want. It's a bit different from your requirement because they have the 2 entities mixed into different sections, but you can still make use of it just with different sort properties.
The moral of the story is don't fight the framework, embrace it :-)
Assume for a moment the following in your header (code below will be slightly sloppy, my apologies):
NSFetchedResultsController *fetchedResultsController1; // first section data
NSFetchedResultsController *fetchedResultsController2; // second section data
Let the table know you want to have 2 sections:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 2; // you wanted 2 sections
}
Give it the section titles:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
return [NSArray arrayWithObjects:@"First section title", @"Second section title", nil];
}
Let the table know how many rows there are per sections:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (section == 0) {
return [[fetchedResultsController1 fetchedObjects] count];
} else if (section == 1) {
return [[fetchedResultsController2 fetchedObjects] count];
}
return 0;
}
Build the cell:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
... // table cell dequeue or creation, boilerplate stuff
// customize the cell
if (indexPath.section == 0) {
// get the managed object from fetchedResultsController1
// customize the cell based on the data
} else if (indexPath.section == 1) {
// get the managed object from fetchedResultsController2
// customize the cell based on the data
}
return cell;
}