I have a simple UITableView Controller that shows CoreData. I'm trying to implement - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath; and having trouble with the animation. The Core Data store gets updated, but the animation is not working.
How can I get the animation to correctly reflect the changes that are happening to the core data objects?
For example:
Initial order:
After item 2 to the top:
or, Initial Order:
After moving item 1 to position 3:
Here's the relevant code:
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
//this implementation is from this tutorial: http://www.cimgf.com/2010/06/05/re-ordering-nsfetchedresultscontroller/
NSMutableArray *things = [[fetchedResultsController fetchedObjects] mutableCopy];
// Grab the item we're moving.
NSManagedObject *thing = [fetchedResultsController objectAtIndexPath:fromIndexPath];
// Remove the object we're moving from the array.
[things removeObject:thing];
// Now re-insert it at the destination.
[things insertObject:thing atIndex:[toIndexPath row]];
// All of the objects are now in their correct order. Update each
// object's displayOrder field by iterating through the array.
int i = 0;
for (NSManagedObject *mo in things)
{
[mo setValue:[NSNumber numberWithInt:i++] forKey:@"order"];
}
NSLog(@"things: %@", things);
[things release], things = nil;
[managedObjectContext save:nil];
}
and the delegate:
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
NSLog(@"didChangeObject:");
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
NSLog(@"ResultsChangeInsert:");
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
I had the same problem, and I fixed it by moving the saving code to a "save" place. i.e.:
I think it's understandable that things would be messed up if you save in the middle of moving things around. And
-(void)setEditing
seems to be a good place to do the saving.btw, thanks for pointing out the cause of the problem!
The problem was caused by the delegate interfering with my reordering implementation. I added a bool before saving my ManagedObjectContext:
and used it to skip out of any of the FetchedResultsController Delegate functions. Not the best solution, but it works for this implementation. I'd be grateful for any comments / answers explaining why this happened.