views:

527

answers:

1

Why is [NSFetchedResultsController performFetch:] crashing when recreating an NSFetchedResultsController with an equivalent NSFetchRequest?

I have an app that has a table view controller of threads (message threads). When you tap a thread it loads another table view controller that uses an NSFetchedResultsController to get all the messages of that thread and display them. I use an NSFetchedResultsController because I can load the messages in the background/delete/add new ones and not worry about displaying them at all.

The second table view controller is used for all the threads, so when I tap back then tap another thread I just delete the current NSFetchedResultsController and set up a new one for the new thread.

Here are the steps to reproduce the CRASH:

  1. Tap a thread so it shows me the messages.
  2. Reload the messages, so the NSFetchedResultsController gets used to show new messages.
  3. Go back.
  4. Tap another thread.
  5. Go back.
  6. Tap first thread.

On tapping the NSFetchedResultsController gets created that is identical to the very first one. (Same cache and everything). Instead of working like it should it gives this error and crashes:

Program received signal: “EXC_BAD_ACCESS”.

NSFetchedResultsController is sending a message to a freed object.

Here is the stack trace:

#0  0x95ffd688 in objc_msgSend
#1  0x0060699b in -[NSFetchedResultsController(PrivateMethods) _computeSectionInfo:error:]
#2  0x00601bf0 in -[NSFetchedResultsController performFetch:]
#3  0x0001c170 in -[CMNewMessagesViewController loadMessagesViewControllerForThread:showProfile:] at CMNewMessagesViewController.m:331

3 is my method

Any Ideas at all? Any help would be much appreciated.


SOLVED!

It was my fault. I was using a sectionNameKeyPath that was derived from another key-value. That is ok as long as the NSFetchRequest is sorted by that key-value. The problem was that it was dynamically generated since I didn't want to waste space in the DB for it. I used an instance variable in the NSManagedObject class for it that was cleaned up by didTurnIntoFault.

Now, I think that the instance variable must have been created then discarded then recreated at some point bringing the sorting of NSFetchedResultsController to a grinding halt.

This explains why not having a sectionNameKeyPath or delegate solved the problem.

Now, I've switched to a saved key-value in the CoreData Object and it seems to work just fine.

A: 

Any chance that you could explain this in more detail please? I'm having the exact same problem, but I have already got the sectionNameKeyPath set to nil:

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];

If you could post your before and after, that would help me understand what you changed to resolve this.

Thanks in advance!

Anonymouslemming
Hi, which part do you want me to explain more ? I don't really have any of this stuff anymore but hopefully I can remember some of it. I've found lots of problems with NSFetchedResultsController so it could be something else too. What do you mean by before and after ?
jasongregori
The only thing I changed was that before I had an instance variable in my NSManagedObject subclass. It was set when someone called it and released when didTurnIntoFault was called. I changed it to use a regular core data attribute instead and that fixed my problems.
jasongregori