views:

332

answers:

2

Hi everyone.

i've been building an app since 1 month using NSFetchedResultsController and i was testing the app on the 3.1.2 SDK. The poblem is that i've been using NSFetchedResultsController everywhere in my app and was working on the 3.1.2 version of the SDK, now my client say that i should make it compatible with the 3.0 version and the deadline is almost there.

But is crashing everytime i change an object handled by the contoller, the application is crashing with very weird errors.

The problem occure when removing the last object in a section and when a change make an object love to another section.

I've been using a sample code from "More iPhone 3 Development Tackling iPhone SDK 3" by Dave Mark and Jeff LaMarche. I've also included some changes from link text

Here is a sample output of the console when the application is crashing.

* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (1) must be equal to the number of sections contained in the table view before the update (2), plus or minus the number of sections inserted or deleted (2 inserted, 0 deleted).' 2010-03-14 16:23:29.758 Instaproofs[5879:207] Stack: ( 807902715, 7364425, 807986683, 811271572, 815059090, 815007323, 211023, 4363331, 810589786, 807635429, 810579728, 3620573, 3620227, 3614682, 3609719, 27337, 810595174, 807686849, 807683624, 839142449, 839142646, 814752238 )

If i knew that NSFetchedResultsController is so buggy, i would never used it.

So basicaly i need the my NSFetchedResultsControllerDelegate to work fine on the 3.0 and above SDKs.

It would be life saver if someone help me figure out what i'm doing wrong.

+1  A: 

It appears from your error messages that you are inserting sections into the table when you should be deleting them. Your tableView dataSource is only supplying one section after the updates even though you have told the tableView to expect a total of four sections.

I don't think this is a case of NSFetchedResultsController being buggy, but rather that it is tricky to implement outside of simple use cases. Your crashes are almost certainly occurring as a result of your controller:didChangeObject:atIndexPath:forChangeType:newIndexPath delegate method. The key to successfully implementing this method (at least in my experience) is to keep in mind that the changeTypes are both object and indexPath driven. This makes "updates" and "moves" tricky conceptually.

Consider the situation where a managed object is changed such that it sorts under a new sectionNameKeyPath. Conceptually, we think of the object as having "moved" to a new section since the fetchedResultsController now sorts it under a new heading in the tableView. If the object's indexPath does not change, however, the fetchedResultsController considers this an "update" and not a "move".

What's worse is that even though the managed object that changed still retains the same indexPath, other objects in the fetchedResultsController may now have new indexPaths because they were bumped around by the change. This means that you will have to manually handle section insertions and section deletions in the "update" section of your delegate method. Similar problems will need to be addressed in the "move" section of your delegate method.

Without trying to explain it in so many words, LaMarche's fix is attempting to address this problem in a generic way that accommodates as many use cases as possible. By trying to understand the problem as it pertains to your use case, you may be able to significantly reduce the complexity of the code that LaMarche uses. Focus specifically on the "update" and "move" sections of your delegate method, as these are the most likely culprits for your problem.

glorifiedHacker
Note: There is one bug in the 3.0 version of NSFetchedResultsController that I am aware of and it is mentioned in the class reference documentation. The bug is only a problem is you aren't specifying a sectionNameKeyPath. You may want to implement the workaround provided in the documentation though, just to be safe.
glorifiedHacker
The post above is extremely helpful. I am having the same problem as the original poster. I have found that reloading the data after any change in - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath works most of the time, althought not 100% of the time. I don't know how significant this is; but hopefully it helps anyone who comes across this post.
Oh Danny Boy
A: 

Check out this resource:

http://iphonedevelopment.blogspot.com/2009/11/i-know-youre-tired-of-hearing-about.html

Helped me tremendously.

Oh Danny Boy