Why UITableView reloadData can not in animate block?

548 views Asked by At

Before, I don't know why, when I reloadData my tableVIew, it takes a very long time.

enter image description here

I have test Log to prove, shows the slow is not because the network:

2016-12-29 14:50:20.958 Eee[1572:25220] lml-info-vc-test-net-began
2016-12-29 14:50:20.958 Eee[1572:25220] lml-info-vc-test-net-end
2016-12-29 14:50:20.972 Eee[1572:25220] lml-info-vc-test-net-animations-reloadData-bigin
2016-12-29 14:50:34.870 Eee[1572:25220] lml-info-vc-test-net-animations-reloadData-end

As we see, the net-began and net-end takes very little time.
But the reloadData-bigin and reloadData-end takes a long time, so I searched the SO, what did the reloadData do? I want to know deeply, not simple answer, I searched always is simple answer, not analyse in depth.

My reloadData code:

//[self.pre_tableView reloadData];
[UIView animateWithDuration:0 animations:^{

     NSLog(@"lml-info-vc-test-net-animations-reloadData-bigin");

     [self.pre_tableView reloadData];
     NSLog(@"lml-info-vc-test-net-animations-reloadData-end");
 } completion:^(BOOL finished) {
     //Do something after that...
     [_pre_tableView.mj_footer endRefreshing];
     [_pre_tableView.mj_header endRefreshing];

 }];

I use animation block, and in the completionHadler to end the refreshing.

I also searched the apple docs for reloadData

In the Discussion:

Call this method to reload all the data that is used to construct the table, including cells, section headers and footers, index arrays, and so on. For efficiency, the table view redisplays only those rows that are visible. It adjusts offsets if the table shrinks as a result of the reload. The table view’s delegate or data source calls this method when it wants the table view to completely reload its data. It should not be called in the methods that insert or delete rows, especially within an animation block implemented with calls to beginUpdates and endUpdates.

Attention

With the attentive sentence:

It should not be called in the methods that insert or delete rows, especially within an animation block

Well! It means I should not in my UIView's animateWithDuration method to reloadData, so I replace my code to below:

[self.pre_tableView reloadData];
[_pre_tableView.mj_footer endRefreshing];
[_pre_tableView.mj_header endRefreshing];

Now it is not slow any more. Very happy, I find the reason.

But, I just want to know why, why can not put reloadData method in animation block ?

And it reloadData did not fail, even takes a long time, in the animate block happens what? then it takes so many time here?


Edit -1

My additional code is below:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return self.pre_dataSource.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:info_TableIdentifier];

    if (cell == nil) {

        cell = [[LMLAgricultureTechCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:info_TableIdentifier];
    }
    //NSLog(@"lml-info-vc-test-cellSetModel-began");
    ((LMLAgricultureTechCell *)cell).model = self.pre_dataSource[indexPath.row];
    //NSLog(@"lml-info-vc-test-cellSetModel-end");
    ((LMLAgricultureTechCell *)cell).indexPath = indexPath;
    ((LMLAgricultureTechCell *)cell).delegate = self;
    ((LMLAgricultureTechCell *)cell).photo_view.delegate = self;

    return cell;

}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // >>>>>>>>>>>>>>>>>>>>> * cell自适应 * >>>>>>>>>>>>>>>>>>>>>>>>
    id model;

    model = self.pre_dataSource[indexPath.row];

    return [self.pre_tableView cellHeightForIndexPath:indexPath model:model keyPath:@"model" cellClass:[LMLAgricultureTechCell class] contentViewWidth:[self cellContentViewWith]];
}
1

There are 1 answers

1
Aviel Gross On

UIView.animateWithDuration... methods can only animate values that are animatable. Although it sometimes feels like magic - it's not really... reloadData is an async method that can not be handled by the animate block the be animated.

If you want to animate the transition you can either use insert/delete/moveRows or use the transitionWithView method of UIView. This method would render the view off-screen completely as it will look after all the changes you put in it's block, than animate transit between the current state of the view and the newly rendered view. The animation itself depends on the options you deliver, and you probably want to use UIViewAnimationOptionsTransitionCrossDissolve.

[UIView transitionWithView:self.pre_tableView 
              duration:0.3 
               options:UIViewAnimationOptionsTransitionCrossDissolve 
            animations: ^{ 
                [self.pre_tableView reloadData];
            } completion: ^(BOOL finished) { 
                ... 
            }];