Search code examples
core-datansfetchedresultscontroller

NSFetchedResultsController only sorting by 1st sort descriptor


I'm seeing an issue where the NSFetchedResultsController is only sorting by the first NSSortDescriptor in the sortDescriptors array when the data changes. It's really infuriating.

I'm using an NSFetchedResultsController to manage a tableview that is displaying a list of items. These items have an inherent order based on the number property, but a user can favorite an item. Favorited items are displayed at the top of the table view, sorted by the number property.

So, the model looks something like this:

@interface Thing : NSManagedObject
    @property (nonatomic, retain) NSNumber *number;
    @property (nonatomic, retain) NSNumber *favorite;
@end

@implementation Thing
    @dynamic number;
    @dynamic favorite;
@end

And I'm configuring my NSFetchedResultsController like so:

- (void)loadView {
    ...
    //
    // configure fetched results controller for the things table view
    NSFetchRequest *fetchThings = [[NSFetchRequest alloc] init];
    fetchChannels.entity = [NSEntityDescription entityForName:NSStringFromClass([Thing class]) 
                                       inManagedObjectContext:[DataManager sharedInstance].managedObjectContext];
    fetchThings.sortDescriptors = @[
    [NSSortDescriptor sortDescriptorWithKey:@"favorite" ascending:NO],
    [NSSortDescriptor sortDescriptorWithKey:@"number" ascending:YES] ];
    
    _fetchController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchThings
                                                           managedObjectContext:[DataManager sharedInstance].managedObjectContext
                                                             sectionNameKeyPath:nil
                                                                      cacheName:nil];
    
    NSError *error = nil;
    if (![_fetchController performFetch:&error]) {
        NSLog(@"error performing fetch! %@", error.localizedDescription);
    }
}

When the table is initially loaded, _fetchController correctly sorts the items, so you could end up with something like this:

- Thing: favorite = YES, number = 2
- Thing: favorite = YES, number = 3
- Thing: favorite = NO, number = 1
- Thing: favorite = NO, number = 4

But if you were to un-favorite Thing Number 2, it only sorts by the 1st sort descriptor, and the list looks like this:

- Thing: favorite = YES, number = 3
- Thing: favorite = NO, number = 2
- Thing: favorite = NO, number = 1
- Thing: favorite = NO, number = 4

Has anyone run into this issue or found a work around for it?

Update

It would appear that if I favorite everything, then unfavorite everything, the sorting works itself out. This leads me to believe this could be a faulting issue? Unfortunately, I'm not sure how to work around that, either.


Solution

  • OK, I figured it out, and it's my own fault.

    Just because the field represents a BOOL doesn't mean it's actually a BOOL. The favorite field in the Thing model is actually an NSNumber, and as such, has 3 states, @(YES), @(NO), and nil. Once I made sure I was initializing the favorite field properly the sorting started working as expected again.