I'm working with a master/detail mechanism. The tableview controller make use of [controller:(NSFetchedResultsController *)controller didChangeObject:...] to refresh the related row. It works great with insertions, and deletion.
Now I would like not to really delete rows, juste "hide" them.
So I add a boolean 'deleted' in my core data model, and my master use a predicate to fetch only "deleted = FALSE".
In the [controller:(NSFetchedResultsController *)controller didChangeObject:...] I need to :
- check for NSFetchedResultsChangeUpdate.
- If so, I need probably to 'refresh' le fetchedResultController (not sure if it can detect that a managedObject which match the predicate does not match anymore),
- I need delete the row from the tableview.
Here is the code :
case NSFetchedResultsChangeUpdate:
// This is fired by saving managedObject.deleted from FALSE to TRUE
// ... so I would like to delete the corresponding row from the tableview
// without reloading the full table.
self.fetchedResultsController = nil;
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
But it doesn't work as expected, and juste crash with error message :
2012-05-31 09:48:23.293 TableViewTest[32701:fb03] CoreData: error:
``Serious application error.
An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:.
Invalid update: invalid number of rows in section 0.
The number of rows contained in an existing section after the update (7)
must be equal to the number of rows contained in that section before the update (7),
plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted)
and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
with userInfo (null)
The message is clear, the NSFetchedResultsController don't return the correct count. By enabling CoreData request log, it seems that in this method, change are not yet commited.
I tried different method :
- make sure that NSFetchedResults really make the request (explicitly call the fetch, deleting cache).
- I tried to specify [fetchRequest includesPendingChanges] to include not yet commited change
But I always have the same problem. Why does it works for insertion and true deletion (insertion and deletion are not commited but are seen by the NSFetchedResultsController).
PS : To illustrate this particular problem I create a new project from Xcode template (using CoreData + MasterController options). You can find it on github https://github.com/arnauddelattre/TableViewTest . You can try to add some row, then selecting a row and clicking on the "Logical deletion".
_
EDIT : Following to Mundi response Mundi suggests me to call save method on the managed context. As you can see, i'm already in the save method, which call [controller didChangeObject]. So, it leads to calling a save in a save.
The strange thing to me, is that it seems working. But I'm afraid of possible side-effects (because of calling save in a save). Is it a "standard" way to achieve what I want ?
And I'm still not understanding why is this behavior different from inserting/true deletion.