Here's a simple example (basically made from "Master-Detail" Xcode template).
I'm trying to move one row ("B") and reload another row ("A1" -> "A2") in a batch update in UITableView.
- (void)awakeFromNib
{
[super awakeFromNib];
self.objects = @[@"B", @"A1"];
}
- (IBAction)boom
{
self.objects = @[@"A2", @"B"];
NSIndexPath *path0 = [NSIndexPath indexPathForRow:0 inSection:0];
NSIndexPath *path1 = [NSIndexPath indexPathForRow:1 inSection:0];
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:@[path1] withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView moveRowAtIndexPath:path0 toIndexPath:path1];
[self.tableView endUpdates];
}
This results in the following exception:
2015-01-14 17:58:51.290 batchtest[34004:806671] *** Assertion failure in -[_UITableViewUpdateSupport _setupAnimationsForNewlyInsertedCells], /SourceCache/UIKit_Sim/UIKit-3318.16.14/UITableViewSupport.m:1216
2015-01-14 17:58:51.335 batchtest[34004:806671] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempt to create two animations for cell'
*** First throw call stack:
(
0 CoreFoundation 0x00946946 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x005cfa97 objc_exception_throw + 44
2 CoreFoundation 0x009467da +[NSException raise:format:arguments:] + 138
3 Foundation 0x00243810 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 118
4 UIKit 0x010b18e5 -[_UITableViewUpdateSupport(Private) _setupAnimationsForNewlyInsertedCells] + 8447
5 UIKit 0x010bb422 -[_UITableViewUpdateSupport _setupAnimations] + 207
6 UIKit 0x00df8bc1 -[UITableView _updateWithItems:updateSupport:] + 2089
7 UIKit 0x00df24a8 -[UITableView _endCellAnimationsWithContext:] + 13867
8 UIKit 0x00e07b6f -[UITableView endUpdatesWithContext:] + 51
9 UIKit 0x00e07b9d -[UITableView endUpdates] + 41
Same thing happens when I try to pass @[path0]
to reloadRowsAtIndexPaths
instead of @[path1]
.
This looks like an iOS bug to me. Is there a way around it? Am I doing something wrong?
It might be better to reload specific rows/cells in the table view. In today's tutorial we will be learning how to do this, luckily, Apple has made this very easy for us.
Step 1: Setup UITableView 1 Create the data. All we need for our data is a simple array of strings. 2 Set datasource and delegate on table view outlet 3 Update Datasource methods. Now that we have our data we need to update the numberOfRowsInSection and cellForRowAt indexPath methods that we added earlier in this tutorial.
If you want to reload multiple rows all you need to do is add the index paths for those rows to the array that we pass to reloadRows. Something like this: Now, if you build and run the app and tap on the row that says four, you will see that it updates.
Launch the app and scroll the tableView by 50 point, which is half height of cell 0, then tap cell 0. If you use iPhone8,7,6, the background of cell 14 becomes red instead of cell 0. You can also find the print "didSelectRowAt: [0, 0]" and "cellForRowAt: [0, 14]".
From my point of view, there is nothing wrong with this exception. The reloadRowsAtIndexPaths:withRowAnimation:
creates an animation for a row being reloaded, and moveRowAtIndexPath:toIndexPath:
also creates an animation. Obviously, UITableView can't handle 2 simultaneous animations and throws an exception.
I guess that passing the UITableViewRowAnimationNone
to the reloadRowsAtIndexPaths:withRowAnimation:
could solve the problem but not sure; still, worth to try.
I'd propose a workaround like this:
[self.tableView moveRowAtIndexPath:path0 toIndexPath:path1];
dispatch_async(dispatch_get_main_queue(), ^{
self.objects = @[@"A2", @"B"];
[self.tableView reloadRowsAtIndexPaths:@[path1]
withRowAnimation:UITableViewRowAnimationAutomatic];
});
or this:
[CATransaction begin];
[CATransaction setCompletionBlock:^{
self.objects = @[@"A2", @"B"];
[self.tableView reloadRowsAtIndexPaths:@[path1]
withRowAnimation:UITableViewRowAnimationAutomatic];
}];
[self.tableView moveRowAtIndexPath:path0 toIndexPath:path1];
[CATransaction commit];
or this:
[UIView animateWithDuration:0.2 animations:^{
[self.tableView moveRowAtIndexPath:path0 toIndexPath:path1];
} completion:^(BOOL finished){
self.objects = @[@"A2", @"B"];
[self.tableView reloadRowsAtIndexPaths:@[path1]
withRowAnimation:UITableViewRowAnimationAutomatic];
}];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With