views:

1557

answers:

6

I make use of NSFetchedResultsController to display a bunch of objects, which are sectioned using dates. On a fresh install, it all works perfectly and the objects are displayed in the table view. However, it seems that when the app is relaunched I get a crash. I specify a cache when initialising the NSFetchedResultsController, and when I don't it works perfectly.

Here is how I create my NSFetchedResultsController:

- (NSFetchedResultsController *)results {
    // If we are not nil, stop here
    if (results != nil)
        return results;

    // Create the fetch request, entity and sort descriptors
    NSFetchRequest *fetch = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
    NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"utc_start" ascending:YES];
    NSArray *descriptors = [[NSArray alloc] initWithObjects:descriptor, nil];

    // Set properties on the fetch
    [fetch setEntity:entity];
    [fetch setSortDescriptors:descriptors];

    // Create a fresh fetched results controller
    NSFetchedResultsController *fetched = [[NSFetchedResultsController alloc] initWithFetchRequest:fetch managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"day" cacheName:@"Events"];
    fetched.delegate = self;
    self.results = fetched;

    // Release objects and return our controller
    [fetched release];
    [fetch release];
    [descriptor release];
    [descriptors release];
    return results;
}

These are the messages I get when the app crashes:

FATAL ERROR: The persistent cache of section information does not match the current configuration.  You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'FATAL ERROR: The persistent cache of section information does not match the current configuration.  You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:'

I really have no clue as to why it's saying that, as I don't believe I'm doing anything special that would cause this. The only potential issue is the section header (day), which I construct like this when creating a new object:

// Set the new format
[formatter setDateFormat:@"dd MMMM"];

// Set the day of the event
[event setValue:[formatter stringFromDate:[event valueForKey:@"utc_start"]] forKey:@"day"];

Like I mentioned, all of this works fine if there is no cache involved. Any help appreciated!

A: 

If you're using the simulator, try resetting it--I'd guess you've changed your entity map and it's getting confused by a leftover cache. If not, you could try doing what the error says:

- (void)applicationWillTerminate:(UIApplication *)application {
    [NSFetchedResultsController deleteCacheNamed:@"Events"];
    //etc
}
eman
Deleting the app just causes the same cycle. Wouldn't deleting the cache on terminate just defeat the purpose of having a cache at all?
Oliver
@Oliver: It defeats part of the purpose of the cache (I'm pretty sure the cache also helps performance during runtime by eliminating fetches). If it works, it's a really kludgy solution, but `NSFetchedResultsController` is still (as of SDK 3.1) quite buggy (I've run into problems with it improperly caching section headers, for instance). I don't see anything wrong with the code you posted, so it could be a temporary solution until you find out what's actually wrong (whether it's in your code or `NSFetchedResultsController`).
eman
A: 

Are you quitting the Simulator using the home button or by terminating the app in Xcode? Maybe the app isn't getting time to finish writing to the cache. Try using the home button to quit the app.

nevan
A: 

How many classes implement the same - (NSFetchedResultsController *)results method, do you use a different cache for each one? I was having the same issue and I think I fix it by using a different cache name fore some clases since I have different NSPredicates.

Jigzat
A: 

I'm having a similar problem. Mine is caused by the fact that I changed the predicate, so the cache doesn't match anymore. If I change the predicate back it works. I fixed it by changing the cache name, but that's pretty weak. I'm trying to figure out where to implement deleteCacheWithName. I can't put it in AppDelegate didFinishLaunchingWithOptions because that gets called after Controller viewWillAppear. And anyways, then I'm deleting it every time. I'd like to figure out how to compare the cache "sets" to see if there's been a change, and if so, then delete it. I'll keep you posted with what I figure out.

Steven Bristol
+4  A: 

I had a similar problem with one of my apps, when the Apple released the new iOS 4.0. Search:

fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:[self managedObjectContext] sectionNameKeyPath:nil cacheName:nil];

And set the value of the parameter cacheName to nil. It worked for me, hope it will for you. Let me know.

IssamTP
For more detail check the documentation for NSFetchedResultsController.
John S. Eddie
A: 

I started getting the same error when I upgraded by MacBook Pro to Snow Leopard 10.6.4 and the latest SDK.

As it turns out, many of us had been using code that wasn't in conformance with the rules, but we didn't know it because CoreData wasn't really behaving in accordance with its own rules.

Specifically, when you fetch things, they get cached, and in 4.0, that cache isn't automatically purged in cases where it was purged in the earlier SDK.

For me, the solution was simple. I just employed the class method that purges the caches. You can specify an individual entity, but I specify nil so it just does them all in this particular piece of start-up code:

[NSFetchedResultsController deleteCacheWithName:nil];

Suddenly, the little app I've worked on only to familiarize myself with CoreData is working again.

Mike V