Please be gentle, this is my first ever post.
When I update a subclassed NSManagedObject and perform a save using a fetched results controller, instead of calling NSFetchedResultsChangeUpdate in "didChangeObject" it calls NSFetchedResultsChangeDelete. The save works and it updates the objects, but then immediately deletes it from the UITableView. If I quit and return, the object re-appears in the tableview with the updates so I know it is saving it to the DB.
I am developing code for a simple task app using XCODE 5. I am using an iPhone 4S and not the simulator to test it. It was working fine until I made some mods to another part of the code (I thought unconnected and now it doesn't work.
I have a sort order and when I update an object and it changed in the sort order, there was a nice animation for the moving of the UITableViewCells....now I have to force a fetch again and do [self.tableView reloadData]. This is a hack as I do not get any animations, but it is the only way I can get it to update:
I have a prepare for segue method:
- (void) prepareForSegue: (UIStoryboardSegue *) segue sender: (id) sender
{
// configure the destination view controller:
if ( [segue.destinationViewController isKindOfClass: [ShowEditTaskTableViewController class]])
{
if ([sender isKindOfClass:[UITableViewCell class]] )
{
NSIndexPath *indexPath = [self.taskTableView indexPathForCell:sender];
[self.taskTableView deselectRowAtIndexPath:indexPath animated:YES];
// Pass the selected task to the new view controller.
ShowEditTaskTableViewController *detailViewController = segue.destinationViewController;
Task *info = [self.fetchedResultsController objectAtIndexPath:indexPath];
detailViewController.editedObject = info;
}
else
{
NSIndexPath *indexPath = [self.taskTableView indexPathForCell:sender];
[self.taskTableView deselectRowAtIndexPath:indexPath animated:YES];
ShowEditTaskTableViewController *detailViewController = segue.destinationViewController;
Task *info = (Task *)[NSEntityDescription insertNewObjectForEntityForName:@"Task" inManagedObjectContext:self.managedObjectContext];
detailViewController.editedObject = info;
}
}
}
There is nothing special here. "Task" is my NSManagedObject.
I have a rewind (EDIT: changed reverse to rewind after comment) segue and before it is called, I set the variables which will be set stored in the editedObject.:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"addNewTaskSave"]) {
// Note: This is an unwind segue to go back to the previous screen.
self.dueDate = self.taskDatePicker.date;
self.description = self.taskDescriptionTextView.text;
self.priority = self.taskPrioritySegment.selectedSegmentIndex;
}
}
and in the RootViewController it calls:
- (IBAction)addNewTaskSave:(UIStoryboardSegue *)segue
{
ShowEditTaskTableViewController *controller = segue.sourceViewController;
controller.editedObject.shortDesc = controller.description;
controller.editedObject.priority = @(controller.priority);
controller.editedObject.dueDate = controller.dueDate;
controller.editedObject.completed = @0;
NSError *error;
if (![self.managedObjectContext save:&error]) {
...
}
.....
}
It uses the standard didChangeObject delegate methods. This worked fine until I clearly changed something.
Now after the save, it sets the NSFetchedResultsChangeDelete option and deletes the table row.
The fix is to add:
self.fetchedResultsController = nil;
if (![[self fetchedResultsController] performFetch:&error]) {
...
}
[self.taskTableView reloadData];
However, this means that what is actually observed is just a straight update of the Table View with no animation.
Without this code, you can observe an animated delete of the table row. If I quit and restart, my edited object is there.
I have scoured SO which has been my constant companion for the last 4 weeks (the time I have been coding for IOS) and cannot find anything on this behaviour.
Any help would be greatly appreciated.
EDIT:
before the save, controller.editedObject isDeleted = NO, isUpdated = YES, so I can't see why it is setting NSFetchedResultsControllerChangeDelete.