Search code examples
iosiphoneobjective-cnsfetchedresultscontroller

NSFetchedResultController doesn't update UITableView when I change the FetchRequest without changing NSSortDescriptor


I have an UITableView and a UISegmentControl in my view controller. The view controller has two segments. When the user clicks on a segment, I refine the data in the viewController, and it should update in the UITableView. This doesn't work.

The data is displayed using a NSFetchedResultsController, whoses datasource is a CoreData table. They use the same NSSortDescriptor, but not the same predicate.

I observed that when I change the NSSortDescriptor, it works, so this objects is the root of the problem.

When the user clicks on a segment, I call this code:

self.fetchedResultsController = nil;
NSError *error;
if (![[self fetchedResultsController] performFetch:&error]) {
        // Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
}

And it updates the NSFetchedResultsController this way:

- (NSFetchedResultsController *)fetchedResultsController {

    if (_fetchedResultsController != nil) {
        return _fetchedResultsController;
    }
    //get the segment index:
    NSUInteger selectedState = self.chooseTableSegmentedControl.selectedSegmentIndex;

    //Update the fetched result consequently:
    NSManagedObjectContext *context = self.managedObjectContext;
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event"
                                              inManagedObjectContext:context];
    [fetchRequest setEntity:entity];
    NSSortDescriptor *dateDescriptor = [[NSSortDescriptor alloc] initWithKey:@"createdAt" ascending:NO];
    NSPredicate *predicate;

    if (selectedState == 0) {
        [fetchRequest setSortDescriptors:@[dateDescriptor]];

    } else if (selectedState == 1) {
        predicate = [NSPredicate predicateWithFormat:
                                  @"postedByUser == 0"];
        [fetchRequest setSortDescriptors:@[dateDescriptor]];

    }
    [fetchRequest setPredicate:predicate];
    [fetchRequest setFetchBatchSize:7];

    NSFetchedResultsController *theFetchedResultsController =
    [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                        managedObjectContext:context
                                          sectionNameKeyPath:nil
                                                   cacheName:@"Root"];
    _fetchedResultsController = theFetchedResultsController;
    _fetchedResultsController.delegate = self;

    return _fetchedResultsController;
}

Any idea? Thanks a lot!


Solution

  • After creating a new fetched results controller and calling performFetch, you have to reload the table view with reloadData. performFetch does not trigger the FRC delegate methods.

    Update: A FRC cache must be deleted when the fetch request changes (using deleteCacheWithName:). But the cache is only useful in connection with a sectionNameKeyPath:, so you can set cacheName:nil as well to solve the problem.