Reputation: 49354
Here is the exception:
Serious application error. Exception was caught during
Core Data change processing: *** -[NSCFArray removeObjectAtIndex:]:
index (0) beyond bounds (0) with userInfo (null)
Here is the relevant code:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
NSMutableArray *array = [[fetchedResultsController fetchedObjects] mutableCopy];
id objectToMove = [[array objectAtIndex:fromIndexPath.row] retain];
[array removeObjectAtIndex:fromIndexPath.row];
[array insertObject:objectToMove atIndex:toIndexPath.row];
[objectToMove release];
for (int i=0; i<[array count]; i++) {
[(NSManagedObject *)[array objectAtIndex:i] setValue:[NSNumber numberWithInt:i] forKey:JKChecklistRow];
}
[array release];
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller
didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath
forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
{
UITableView *tableView = self.tableView;
switch(type) {
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;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
[self.tableView endUpdates];
}
I have a suspicion that the crash has something to do with the Core Data store getting out of sync with the unsaved context. If I save the context in the -tableView:moveRowAtIndexPath:fromIndexPath:toIndexPath:
method, the program crashes faster, I haven't been able to figure out why, though.
Upvotes: 1
Views: 2453
Reputation: 49354
I figured it out. Actually, Jeff LaMarche figured it out.
The bit of code that saved me:
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
// In the simplest, most efficient, case, reload the table view.
if (!self.tableView.editing)
[self.tableView reloadData];
}
Since I was moving these rows around in the table-view itself, the view does already reflects the changes. When I updated my data source, my delegate would try and rearrange rows that had already been moved, causing the crash.
Upvotes: 1
Reputation: 31
If you use sections while moving rows, NSFetchedResultsController and the table view get out o f sync immediately. I guess it's a bug in this class. So it's not the unsaved context in my experience.
One of the problems was, that the index paths are not up to date after the move and so the number of rows on that path is no longer correct, which leads to the "index beyond bounds". Let's say you have an index to (1,1) and remove the row at (1,1). The index points stil to (1,1), but the content for the section 1 is no longer the same etc. etc.
Just make it visible for you with something like NSUInteger tableSectionCount = [self.tableView numberOfSections]; NSUInteger frcSectionCount = [[controller sections] count]; NSLog(@"tableSectionCount: %d",tableSectionCount); NSLog(@"frcSectionCount: %d",frcSectionCount); and you will see.
Furthermore it's very difficult to find all the cases where the NSFRC is using NSFetchedResultsChangeMove or NSFetchedResultsChangeUpdate. It depends strongly from if it's necessary to reorder the rows. At the end you have to synchronise tabel view and NSFRC by yourself for every specific case. It costs me three days at the end to figure it out.
Very helpful is this: http://iphonedevelopment.blogspot.com/2009/11/one-fix-to-nsfetchedresultscontroller.html. I've sent the author some more findings, so I guess there will be updates on it.
But again: the key is keeping the sections up to date on your own.
Good luck! Gerd
Upvotes: 1