NSFetchedResultsController crashing on performFetch: when using a cache

24,953

Solution 1

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.

Solution 2

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.

Solution 3

Straight from the documentation for NSFetchedResultsController:

Modifying the Fetch Request

You cannot simply change the fetch request to modify the results. If you want to change the fetch request, you must:

  1. If you are using a cache, delete it (using deleteCacheWithName:). Typically you should not use a cache if you are changing the fetch request.

  2. Change the fetch request.

  3. Invoke performFetch:.

Solution 4

I encountered a similar problem. When I inspected the Debugger Console, it showed what the cached objects and the fetched objects were so that I could figure out why they are inconsistent. In my case it was due to a different predicate.

Since the values in my predicate are not dynamic, I could specify a different cache name for each predicate. That will create a cache for each 'type' I specify.

I suppose you will have to assess your need to have the cache. To specify nil, means that a fetch is made in every call.

I figured out that the error occurs only when the fetch request have some changes. If you are creating a new NSFetchRequest OR changing the predicate OR sort descriptor, then you should delete the cache or use a different cache. Otherwise, ensure that you have the same NSFetchRequest or make sure that your NSFetchedResultsController is retained and that should solve your problem.

Solution 5

The exception still occurs with Xcode 7 (beta 4):

You have illegally mutated the NSFetchedResultsController's fetch request, its predicate, or its sort descriptor without either disabling caching or using +deleteCacheWithName:

NOTE: This is with an unmodified Xcode "Template" Master-Detail iOS app with standard Xcode CoreData "boiler-plate" code created with Xcode 7 and using the latest (iOS 9) deployment target.

I noticed it first when I restarted my app in the simulator. I had been starting and stopping the app several times via Xcode and then it happened; and it kept happening. I decided to do some experiments, and the results:

  • Every time I stopped the app in the simulator, I would get the exception on a subsequent launch.
  • Every time I stopped the app using the simulator's Home button, I was able to launch it again successfully.

The issue can still be fixed as follows, using one or the other of the following methods:

  • In the AppDelegate's application didFinishLaunchingWithOptions method, add the following Swift NSFetchedResultsController.deleteCacheWithName(nil) or Objective-C [NSFetchedResultsController deleteCacheWithName:nil]; code. This clears out the corrupted cache.
  • In the Simulator, from the Simulator menu, select Reset Content and Settings. This fixes the problem, but you lose your test data.

I also believe that this is an artifact of running via Xcode and stopping the app prior to it being able to clean up. I've not seen this in the actual device.

Share:
24,953

Related videos on Youtube

Oliver
Author by

Oliver

Updated on August 07, 2020

Comments

  • Oliver
    Oliver over 3 years

    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!

  • Oliver
    Oliver about 14 years
    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?
  • shosti
    shosti about 14 years
    @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).
  • John S. Eddie
    John S. Eddie over 13 years
    For more detail check the documentation for NSFetchedResultsController.
  • Ward
    Ward about 13 years
    nil worked for me - app taken from 3.x to 4.x threw the same error.
  • brownandi
    brownandi over 12 years
    What I do is build a cache name based on the query. In my case, it is usually: @"%@-%@-%@", [entity name], queryId, sortOption.
  • jimmyb
    jimmyb over 11 years
    [NSFetchedResultsController deleteCacheWithName:nil]; worked for me...previously i was doing deleteCachWithName:someName. when i switched someName to nil, worked like a charm. realized at that point that I was creating the fetchRequest with a different cacheName than i was deleting... in the end, i fixed my typo and explicitly delete with the cacheName, but nil also worked, for obvious reasons.
  • IssamTP
    IssamTP almost 10 years
    [OT] LOL. Still getting rep from a 4yo answer.[/OT]
  • Shiprack
    Shiprack about 9 years
    I'm not convinced setting the cache to nil is the optimal answer. Aren't we just disabling all caching then, giving up performance?