Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recipes for changing the Fetch Request for NSFetchedResultsController and reloading table data

From apple doc Modifying the Fetch Request I see that is possible to change the NSFetchRequest for NSFetchedResultsController. Steps are easy to set up.

After invoking performFetch: I think there is the need to call reloadData on the the table view. How to perform such call?

Reading some stackoverflow topics, I've seen that calling that method should work in most cases. But is there a right way to do it?

In How to switch UITableView's NSFetchedResultsController (or its predicate) programmatically?, TechZen wrote that:

Just make sure to send the tableview itself a beginUpdates before you swap controllers and then an endUpdates when you are done. This prevents the table from asking for data in the narrow window when the FRC are being swapped out. Then call reloadData.

Could you explain exactly what does it mean?

like image 548
Lorenzo B Avatar asked Jan 17 '23 22:01

Lorenzo B


1 Answers

Assuming that the logic to generate the correct fetch (some kind of conditional statement) is in the getter of your NSFetchedResultsController instance. Then it is really easy

self.fetchedResultsController = nil; // this destroys the old one
[self.tableview reloadData]; 
// when the table view is reloaded the fetchedResultsController will be lazily recreated

Edit: adding complete code sample of something I've done. Basically I have a NSDictionary entityDescription that hold values to customize the creation of a NSFetchedResultsController. If I want to change the fetchRequest I change my entityDescription variable to indicate the new values and override the setter to reset the fetchedResultsController and reload the table. It gives you the basic idea.

- (NSFetchedResultsController *)fetchedResultsController 
{
    if (__fetchedResultsController != nil) {
        return __fetchedResultsController;
    }
    if (self.entityDescription == nil) {
        return nil;
    }
    // Set up the fetched results controller.
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[self.entityDescription objectForKey:kEntityName]];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.
    if ([[self.entityDescription objectForKey:kEntitySortField] isEqualToString:@"null"] == NO) {
        NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:[self.entityDescription objectForKey:kEntitySortField] ascending:YES];
        NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
        [fetchRequest setSortDescriptors:sortDescriptors];
    }

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
                                                                                                managedObjectContext:self.moc sectionNameKeyPath:nil cacheName:nil];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    NSError *error = nil;
    if (![self.fetchedResultsController performFetch:&error]) {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }

    return __fetchedResultsController;
}

- (void)setEntityDescription:(NSDictionary *)entityDescription
{
    _entityDescription = entityDescription;
    self.fetchedResultsController = nil;
    [self.tableView reloadData];
}
like image 167
agilityvision Avatar answered Jan 31 '23 09:01

agilityvision