views:

302

answers:

1

I am using NSFetchedResultsController along with a UITableViewController.

I've created a transient field in my Core Data model to use as a label for my UITableView sections. The name of the field is "sectionIndex". In my application, a "Client" entity has many "Jobs" (1 to many) - so my query to retrieve Jobs groups them (via section) by their associated "Client's" name.

I've implemented this method in my code base as a Category on the 'Job' entity.

@implementation Job (TransientMethods)

- (NSString*)sectionIndex {
    NSLog(@"JobWrapper.Job.sectionIndex: %@", self.client.name);
    return self.client.name;
}

@end

and the string "sectionIndex" is passed to the init method for NSFetchedResultsController as the sectionNameKeyPath argument.

If I erase the app from the simulator - then the first time the application runs, the front page of Jobs correctly retrieves and groups the Jobs by the Job's Client.name per the sectionIndex method listed here. In the logs, I can literally see this sectionIndex method invoked multiple times.

However, subsequent runs of the application do NOT invoke the sectionIndex method ... and yet, the section labels still show up with the values from the last run. How is that happening? Is there some magic caching going on between runs?

That behavior then leads to a bigger problem. While looking at the UITableView, if I release and alloc the NSFetchedResultsController with a slightly different predicate and if the result set is the SAME SIZE, ... then these same, original section names show up for all of the NEW results!

And of course, there are no new log entries. This implies the columns are never being looked up which implies the code never invokes or looks up the transient fields. It is as though those fields are not faulting.

Now, if the alternate query returns a DIFFERENT number of results, then the sections names ARE loaded. IE: in that case, the logs show - on every bar button push - the 'sectionIndex' method being invoked and the corresponding labels showing up in the UITableView.

This is crazy - if I have 2 "active" Jobs and 2 "inactive" Jobs and I am using a bar button to switch back and forth between corresponding queries ... then whichever section labels were associated with the initial query show up for all subsequent table views.

It seems that the sectionNameKeyPath field is only invoked by the FetchedResultsController when there is a different # of results in the result set? The actual results are different - the Job names display correctly in the actual rows - but again, I don't think the section labels are faulting or asking the NSFetchedResultsController for the section labels correctly. I am using the following:

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    int count = [[results_ sections] count];
    if (count > section) {
        id <NSFetchedResultsSectionInfo> sectionInfo = [[results_ sections] objectAtIndex:section];
        return [sectionInfo name];
    }
    return nil;
}

where results_ is the NSFetchedResultsController that I am re building for each query.

Am I missing something? Is there a way to manually clear that Core Data cache so that it stops being so smart and, on every query, surely looks up the sectionNameKeyPath?

For what its worth, I unchecked the "Transient" option for the fields in the xcdatamodel but I'm getting the same results.

One final anomally from this is that when I create the first Job as Inactive (not the default startup view) - if I also then create an Active job ... the Inactive section label sticks to both. Furthermore, when I shutdown the application and start over ... the Inactive section label still shows up --- even though, on the title screen, I am displaying the Active Job which should be showing completely different label.

I can't but think this is a Core Data problem. It makes no sense that restarting the application is returning data so out of whack.

+2  A: 

Per Marcus S. Zarra's comment, I set the cacheName to nil:

results_ = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
            managedObjectContext:context_ 
            sectionNameKeyPath:@"sectionIndex" 
            cacheName:nil];
Luther Baker