Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView reload and move rows in same batch update results in 'Attempt to create two animations for cell'

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?

like image 775
Vadim Yelagin Avatar asked Jan 14 '15 12:01

Vadim Yelagin


People also ask

Is it better to reload specific rows/cells in the table view?

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.

How to create a UITableView in Laravel?

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.

How do I reload multiple rows at once?

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.

How to get the background color of cell 14 in Tableview?

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]".


1 Answers

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];
}];
like image 74
Nikolay Mamaev Avatar answered Sep 25 '22 02:09

Nikolay Mamaev