sash
sash

Reputation: 8715

Order when using sectionNameKeyPath in NSFetchedResultsController

In Core Data I have one to many relationship - each layout has many lines:

enter image description here

I am trying to display data inside a table view by grouping into layouts:

Layout Nr 2342 (with orderPosition 1)
    Line 1
    Line 2
    Line …
Layout Nr 2123 (with orderPosition 2)
    Line 1
    Line …
…

I am using NSFetchedResultsController that I create like this:

NSEntityDescription *entity = [NSEntityDescription entityForName:@“Line” inManagedObjectContext:managedObjectContext];

NSSortDescriptor *orderPositionDescriptor = [[NSSortDescriptor alloc] initWithKey:@"layout.orderPosition" ascending:YES];

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setSortDescriptors:@[orderPositionDescriptor]];
[fetchRequest setEntity:entity];

NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"section=='my_section'"]];
[fetchRequest setPredicate:predicate];

self.fetchController = [[NSFetchedResultsController alloc]
                                          initWithFetchRequest:fetchRequest
                                          managedObjectContext:managedObjectContext
                                          sectionNameKeyPath:@"layout.groupNumber"
                                          cacheName:nil];

So I set fetch controller to group in sections by layout groupNumber, I also set sort descriptor to order by layout position (each layout has its own position). As soon as data is added to core data, it is displayed in the table view. Everything works great, till the moment when I try to change NSFetchRequest predicate of the existing NSFetchedResultsController:

 NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"section=='%@'",section]];
 [self.fetchController.fetchRequest setPredicate:predicate]; 

I set exactly the same section in the predicate as it was already set and the data after performFetch displayed in the table is still the same, but layouts (table sections) changes position in the table and lines are displayed in wrong layouts (basically no oder). I figured out that if I set the first sort descriptor the same as sectionNameKeyPath - "layout.groupNumber", then everything works even if I change predicate. But obviously it is not ordered by orderPosition what I want to achieve. Is there any solution for that? Any help would be appreciated.

Upvotes: 0

Views: 526

Answers (2)

andrewbuilder
andrewbuilder

Reputation: 3791

If you are using sections in your table view, and sorting your table view data, it is important to understand that the first sort descriptor must be identical to the sectionNameKeyPath.

As such I recommend you change your code to be something similar to this...

    NSEntityDescription *entity = [NSEntityDescription entityForName:@“Line” inManagedObjectContext:managedObjectContext];

//new line of code following...
    NSSortDescriptor *sectionNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"layout.groupNumber" ascending:YES];
    NSSortDescriptor *orderPositionDescriptor = [[NSSortDescriptor alloc] initWithKey:@"layout.orderPosition" ascending:YES];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
//altered line of code following...
    [fetchRequest setSortDescriptors:@[sectionNameDescriptor, orderPositionDescriptor]];
    [fetchRequest setEntity:entity];

    NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"section=='my_section'"]];
    [fetchRequest setPredicate:predicate];

    self.fetchController = [[NSFetchedResultsController alloc]
                                      initWithFetchRequest:fetchRequest
                                      managedObjectContext:managedObjectContext
                                      sectionNameKeyPath:@"layout.groupNumber"
                                      cacheName:nil];

I have read about this but cannot recall where... so no documentation reference I'm sorry.

Does this help?

Upvotes: 1

sash
sash

Reputation: 8715

I found a workaround of my problem. Because each layout group number has unique order position, solution is to group not by groupNumber, but by orderPosition. In that case I can specify orderPosition as the first (and the only) sort descriptor. In case someone else has other better solution, it would be still interesting to hear it.

NSEntityDescription *entity = [NSEntityDescription entityForName:@“Line” inManagedObjectContext:managedObjectContext];

NSSortDescriptor *orderPositionDescriptor = [[NSSortDescriptor alloc] initWithKey:@"layout.orderPosition" ascending:YES];

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setSortDescriptors:@[orderPositionDescriptor]];
[fetchRequest setEntity:entity];

NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"section=='my_section'"]];
[fetchRequest setPredicate:predicate];

self.fetchController = [[NSFetchedResultsController alloc]
                                          initWithFetchRequest:fetchRequest
                                          managedObjectContext:managedObjectContext
                                          sectionNameKeyPath:@"layout.orderPosition"
                                          cacheName:nil];

Upvotes: 0

Related Questions