Turns out I was coming at this wrong. The solution I found was to add and remove items from the array as usual, and then to call insertRowsAtIndexPaths:withRowAnimation:
, reloadRowsAtIndexPaths:withRowAnimation:
, and deleteRowsAtIndexPaths:withRowAnimation:
as appropriate for each row added, changed, or moved. The fault in my previous plan was the thought that I should wait until all the changes and been made, and then call each of those methods only once in a beginUpdates
/endUpdates
block. Turns out the block wasn't actually necessary, as the modification methods can be called outside of them.
It was much easier to call each method once for each cell inserted, updated, or deleted, than to calculate all the changes at the end and commit them at once. Was just too confusing, error-prone, and inefficient to try to do it all at once.
So the code I ended up with looks like this:
if (parsedItem.savedState == ItemModelSavedStateInserted) {
// It's a new entry. Insert it.
[items addObject:parsedItem];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:items.count - 1 inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
} else {
// It's an existing entry. Find it in the portal and move it, if necessary.
NSUInteger foundAt = [items
indexOfObject:parsedItem
inRange:NSMakeRange(currentItemIndex, items.count - currentItemIndex - 1)
];
if (foundAt == currentItemIndex) {
// It hasn't moved!
if (parsedItem.savedState == ItemModelSavedStateUpdated) {
// It was updated, so replace it.
[items replaceObjectAtIndex:currentItemIndex withObject:parsedItem];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:currentItemIndex inSection:0]] withRowAnimation:UITableViewRowAnimationMiddle];
}
} else {
// It has shifted position.
if (foundAt != NSNotFound) {
// It has moved.
[items removeObjectAtIndex:foundAt];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:foundAt inSection:0]] withRowAnimation:UITableViewRowAnimationBottom];
}
// Need to insert it.
[items insertObject:parsedItem atIndex:currentItemIndex];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:currentItemIndex inSection:0]] withRowAnimation:UITableViewRowAnimationTop];
}
}