runmad
runmad

Reputation: 14886

MagicalRecord NSFetchesResultsController section grouping and sorting + within section as well

I'm using MagicalRecord to create an NSFetchedResultsController for a table.

I've got NSManagedObjects that contain groups of people, here are two examples:

ContactGroup *everyoneContactGroup = [ContactGroup findFirstByAttribute:@"groupId" withValue:@"<GROUPID>"];
if (!everyoneContactGroup) {
    everyoneContactGroup = [ContactGroup createEntity];
    [everyoneContactGroup setGroupId:@"<GROUPID>"];
    [everyoneContactGroup setGroupName:@"Everyone"];
    [everyoneContactGroup setGroupSortOrder:@1]; // sort order within section
    [everyoneContactGroup setGroupType:@1];
    [everyoneContactGroup setGroupTypeName:@"Smart Groups"];
    [everyoneContactGroup setGroupTypeSortOrder:@0]; // sort order for groups
}

ContactGroup *closeFriendsContactGroup = [ContactGroup findFirstByAttribute:@"groupId" withValue:@"<GROUPIDCLOSEFRIENDS>"];
if (!closeFriendsContactGroup) {
    closeFriendsContactGroup = [ContactGroup createEntity];
    [closeFriendsContactGroup setGroupId:@"<GROUPIDCLOSEFRIENDS>"];
    [closeFriendsContactGroup setGroupName:@"Close Friends"];
    [closeFriendsContactGroup setGroupSortOrder:@2];
    [closeFriendsContactGroup setGroupType:@2];
    [closeFriendsContactGroup setGroupTypeName:@"Custom Groups"];
    [closeFriendsContactGroup setGroupTypeSortOrder:@10];
}

ContactGroup *familyContactGroup = [ContactGroup findFirstByAttribute:@"groupId" withValue:@"<GROUPIDFAMILY>"];
if (!familyContactGroup) {
    familyContactGroup = [ContactGroup createEntity];
    [familyContactGroup setGroupId:@"<GROUPIDFAMILY>"];
    [familyContactGroup setGroupName:@"Family"];
    [familyContactGroup setGroupSortOrder:@1];
    [familyContactGroup setGroupType:@2];
    [familyContactGroup setGroupTypeName:@"Custom Groups"];
    [familyContactGroup setGroupTypeSortOrder:@10];
}

The above should show up as follows:

enter image description here

As you can see, the contact group "Everyone" should be grouped into a section of its own and should appear as the first group in the order of the groups.

The second and third contact group above should be grouped into a section together and this section should appear below the other section with one group in it. Inside this group ("Custom Groups") each contact group should be sorted by their groupSortOrder.

Here's my NSFetchedResultsController code:

- (NSFetchedResultsController *)fetchedResultsController {
    if (!fetchedResultsController) {
        fetchedResultsController = [ContactGroup fetchAllSortedBy:@"groupTypeSortOrder,groupSortOrder"
                                                           ascending:YES
                                                       withPredicate:nil
                                                             groupBy:@"groupTypeName"
                                                            delegate:self];
    }
    return fetchedResultsController;
}

I have tried various combinations but cannot get the sort order both for each table view section (group of contact groups) and within each table view section. I know you can add comma-delimited sort attributes, but I just cannot get the combination right. Anyone know if it's possible to achieve what I want with MagicalRecord or do I have to roll some non-MR code .

Thanks in advance for any input and help!

UPDATE:

Here's the SQL being generated by Core Data:

CoreData: sql: 
SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZGROUPID,  t0.ZGROUPNAME, t0.ZGROUPSORTORDER, 
t0.ZGROUPTYPE, t0.ZGROUPTYPENAME, t0.ZGROUPTYPESORTORDER 
FROM ZTCONTACTGROUP t0 
ORDER BY t0.ZGROUPTYPESORTORDER, t0.ZGROUPSORTORDER

UPDATE:

So I have tried with grouping by groupTypeSortOrder and it works correctly now. However, not I cannot get the section name to appear correctly as it will appear with the numbers for groupTypeSortOrder instead. Any ideas?

- (NSFetchedResultsController *)fetchedResultsController {
    if (!fetchedResultsController) {
        fetchedResultsController = [ContactGroup fetchAllSortedBy:@"groupTypeSortOrder,groupSortOrder"
                                                           ascending:YES
                                                       withPredicate:nil
                                                             groupBy:@"groupTypeSortOrder"
                                                            delegate:self];
    }
    return fetchedResultsController;
}

Upvotes: 2

Views: 3075

Answers (1)

Martin R
Martin R

Reputation: 540075

I haven't worked with MagicalRecord yet, but I assume that the groupBy: parameter corresponds to the sectionNameKeyPath: parameter of NSFetchedResultsController.

If a key is specified as sectionNameKeyPath, then the fetch request must have a first sort descriptor using the same key (or a key generating the same relative ordering).

Therefore, using groupTypeSortOrder as first sort key and as groupBy: parameter is the correct way.

Now, to display the group names instead of numbers as section headers, you can modify the titleForHeaderInSection method, which normally looks like this:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.controller sections] objectAtIndex:section];
    return [sectionInfo name];
}

But [sectionInfo name] is the value of the groupTypeSortOrder, because that has been specified as sectionNameKeyPath (or groupBy). If you modify the method like this:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.controller sections] objectAtIndex:section];
    return [[[sectionInfo objects] objectAtIndex:0] groupName];
}

the groupName attribute is displayed as section header instead.

Upvotes: 3

Related Questions