views:

1770

answers:

2

I've come across this issue in my application, and have reproduced it using Apple's CoreDataBooks codebase with 0 modifications to the code. The problem is if you make an edit to a managed object, and save the context, with the result being a section with only one row now having no rows, and a new section created with the resulting object added to it, then you get the invalid update exception. It also seems to depend on the ordering of the rows.

To recreate follow these steps:

  1. Open a new instance of CoreDataBooks example
  2. Edit Richard Dawkins book, "The Selfish Gene" and change the author to Ben. Save it. If you return to the main view you'll notice that the book is under a new section named Ben.
  3. Edit this book again, and change the author to Doug. Save it. You'll get the following exception:

    2009-10-01 15:14:29.050 CoreDataBooks[10898:20b] *** Assertion failure in -[UITableView_endCellAnimationsWithContext:], /SourceCache/UIKit/UIKit-963.10/UITableView.m:729 2009-10-01 15:14:29.051 CoreDataBooks[10898:20b] Serious application error.  Exception was caught during Core Data change processing: Invalid update: invalid number of rows in section 1.  The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted). with userInfo (null)
    

I'd post the code from my own app to make sure I'm not missing any required delegate methods, except as the example above shows it's an issue which affects Apple's CoreDataBooks example straight off the shelf. The NSFetchedResultsController delegate methods are all implemented as per their own examples. Their code doesn't seem to forget to handle newly created sections either, as it works in other cases with different section orderings.

Any help would be appreciated. Example modified code from the CoreDataBooks example would be great.

+1  A: 

One recommendation is that you completely delete the application from your iPhone and/or reset the Simulator, to ensure that you don't have any remnants of a corrupted data store.

After you delete the app or reset the Simulator, recompile this app from scratch. This will create a fresh copy of the application and, more importantly, a fresh data store.

Re-run your test after doing that, to see if you run into the same problem.

Alex Reynolds
Thanks. I've tried that already, and just tried again to confirm. Same error. Reproducing it takes about 10 seconds if it helps to see the error for yourself.
thedob
You're right, I get the same crash and same error. I would recommend that you file a bug report at http://bugreport.apple.com. I'll try to take a look later to see if I can find out anything.
Alex Reynolds
Thanks for the confirmation. Filed a bug report with Apple, and will post here if I hear anything back.
thedob
Have you heard anything back? I'm guessing no somehow.
sbwoodside
+1  A: 

The way to fix this seems to be to change these lines in the table updates section of the RootViewController:

    case NSFetchedResultsChangeMove:
  [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];

  // Reloading the section inserts a new row and ensures that titles are updated appropriately.
  [tableView reloadSections:[NSIndexSet indexSetWithIndex:newIndexPath.section] withRowAnimation:UITableViewRowAnimationFade];
   break;

to:

         case NSFetchedResultsChangeMove:
      [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
      [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
      break;

for some reason. The problem seems to come from deleting the last row in a section; it appears that unless you add the extra insertRows, the UITableView freaks out over the fact that the section which has been deleted suddenly gains a whole bunch of extra rows.

Took me hours to figure that one out....

Geebs
Hmmm, that's still not fixing the issue for me. Though it is giving me a different number of rows reported in the crash message. Did you reproduce using the same steps (Rename Richard Dawkins -> Ben -> Save -> Edit it again -> Rename Ben to Doug)? I get this error message: invalid number of rows in section 1. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted). with userInfo (null)
thedob
You're right, I fixed a similar bug but was able to reproduce your one subsequently. However, changing the line [tableView reloadSections:[NSindexset indexSetWithIndex:newIndexPath.section...... to [tableView reloadSections:[NSindexset indexSetWithIndex:indexPath.section...... fixes your bug, and still actually works. Give that a try.
Geebs
Hmm, I messed around with that a bit further and still managed to get it to break. Oddly, deleting the reloadSections line ALTOGETHER results in an App which doesn't crash and still updates the sections and rows properly. I've updated the solution above to show what my NSFetchedResultsChangedMove: now looks like.
Geebs
Great work Geebs. Have been digging through some code for hours until this fixed the issue for me. +1
Miha Hribar