UITableView reloadData、reloadSections:withRowAnimation: 和 reloadRowsAtIndexPaths:withRowAnimation: 的

Posted

技术标签:

【中文标题】UITableView reloadData、reloadSections:withRowAnimation: 和 reloadRowsAtIndexPaths:withRowAnimation: 的性能【英文标题】:Performance of UITableView reloadData, reloadSections:withRowAnimation: and reloadRowsAtIndexPaths:withRowAnimation: 【发布时间】:2015-08-03 22:45:42 【问题描述】:

我构建了一个测试应用程序来测试这三种方法在重新加载表格视图时的性能。

//
//  ViewController.m
//  TableViewSample
//
//  Created by Antonio081014 on 8/2/15.
//  Copyright (c) 2015 Antonio081014.com. All rights reserved.
//

#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) NSArray *listOfCards;
@property (nonatomic, strong) NSIndexPath *selectedIndexPath;
@end

@implementation ViewController

- (void)viewDidLoad 
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    NSMutableArray *list = [NSMutableArray array];
    for (int i=0; i<15; i++) 
        NSString *carName = [NSString stringWithFormat:@"Car%d", arc4random() % 15];
        [list addObject:carName];
    
    self.listOfCards = list;
    self.tableView.delegate = self;
    self.tableView.dataSource = self;
    self.selectedIndexPath = nil;

    UIBarButtonItem *table = [[UIBarButtonItem alloc] initWithTitle:@"Table" style:UIBarButtonItemStylePlain target:self action:@selector(reloadTable:)];
    UIBarButtonItem *section = [[UIBarButtonItem alloc] initWithTitle:@"Section" style:UIBarButtonItemStylePlain target:self action:@selector(reloadSection:)];
    UIBarButtonItem *indexPath = [[UIBarButtonItem alloc] initWithTitle:@"IndexPath" style:UIBarButtonItemStylePlain target:self action:@selector(reloadRow:)];

    self.navigationItem.rightBarButtonItems = @[table, section, indexPath];
//    self.navigationController.navigationItem.rightBarButtonItems = @[table, section, indexPath];


- (void)reloadTable:(UIBarButtonItem *)barItem

    [self.tableView reloadData];


- (void)reloadRow:(UIBarButtonItem *)barItem

    [self reloadRowAtIndexPath:self.selectedIndexPath forBarButtonItem:barItem];


- (void)reloadSection:(UIBarButtonItem *)barItem

    [self reloadSectionAt:0 forBarButtonItem:barItem];


- (void)reloadRowAtIndexPath:(NSIndexPath *)indexPath forBarButtonItem:(UIBarButtonItem *)barItem

    if (indexPath) 
        [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    


- (void)reloadSectionAt:(NSUInteger)section forBarButtonItem:(UIBarButtonItem *)barItem

    [self.tableView reloadSections:[[NSIndexSet alloc] initWithIndex:section] withRowAnimation:UITableViewRowAnimationAutomatic];



- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

    NSLog(@"Asking Number of Sections in TableView");
    return 1;


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

    NSLog(@"Asking Number of Rows in Section");
    return self.listOfCards.count;


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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

    NSString *carName = self.listOfCards[indexPath.row];
    cell.textLabel.text = carName;

    return cell;


- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

    self.selectedIndexPath = indexPath;
    NSLog(@"Did Select Cell %@", indexPath);


- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath

    self.selectedIndexPath = nil;
    NSLog(@"Did Deselect Cell %@", indexPath);


- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

    NSLog(@"Will Display Cell %@", indexPath);


- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath

    NSLog(@"Did End Display Cell %@", indexPath);


- (void)tableView:(UITableView *)tableView didHighlightRowAtIndexPath:(NSIndexPath *)indexPath

    NSLog(@"Did Highlight Cell %@", indexPath);


@end

三个方法调用时的日志。

重新加载数据 2015-08-03 11:00:51.556 TableViewSample [324:90811] 是否结束显示单元长度 = 2,路径 = 0 - 11 2015-08-03 11:00:51.558 TableViewSample[324:90811] 是否结束显示单元长度 = 2,路径 = 0 - 10 2015-08-03 11:00:51.559 TableViewSample[324:90811] 结束显示单元 长度 = 2,路径 = 0 - 9 2015-08-03 11:00:51.560 TableViewSample [324:90811] 是否结束显示单元长度 = 2,路径 = 0 - 8 2015-08-03 11:00:51.560 TableViewSample[324:90811] 结束显示单元 长度 = 2,路径 = 0 - 7 2015-08-03 11:00:51.560 TableViewSample [324:90811] 是否结束显示单元长度 = 2,路径 = 0 - 6 2015-08-03 11:00:51.561 TableViewSample[324:90811] 是否结束显示单元 长度 = 2,路径 = 0 - 5 2015-08-03 11:00:51.561 TableViewSample[324:90811] 是否结束显示单元 长度 = 2,路径 = 0 - 4 2015-08-03 11:00:51.562 TableViewSample [324:90811] 是否结束显示单元长度 = 2,路径 = 0 - 3 2015-08-03 11:00:51.563 TableViewSample [324:90811] 是否结束显示单元长度 = 2,路径 = 0 - 2 2015-08-03 11:00:51.563 TableViewSample[324:90811] 是否结束显示单元 长度 = 2,路径 = 0 - 1 2015-08-03 11:00:51.564 TableViewSample [324:90811] 是否结束显示单元长度 = 2,路径 = 0 - 0 2015-08-03 11:00:51.564 TableViewSample [324:90811] 询问 TableView 中的节数 2015-08-03 11:00:51.565 TableViewSample [324:90811] 询问部分中的行数 2015-08-03 11:00:51.566 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 0 2015-08-03 11:00:51.567 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 1 2015-08-03 11:00:51.567 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 2 2015-08-03 11:00:51.568 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 3 2015-08-03 11:00:51.569 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 4 2015-08-03 11:00:51.569 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 5 2015-08-03 11:00:51.570 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 6 2015-08-03 11:00:51.571 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 7 2015-08-03 11:00:51.572 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 8 2015-08-03 11:00:51.573 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 9 2015-08-03 11:00:51.573 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 10 2015-08-03 11:00:51.574 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 11 重新加载部分 2015-08-03 11:02:21.641 TableViewSample [324:90811] 询问 TableView 中的节数 2015-08-03 11:02:21.642 TableViewSample [324:90811] 询问 TableView 中的节数 2015-08-03 11:02:21.643 TableViewSample [324:90811] 询问部分中的行数 2015-08-03 11:02:21.647 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 0 2015-08-03 11:02:21.649 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 1 2015-08-03 11:02:21.651 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 2 2015-08-03 11:02:21.653 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 3 2015-08-03 11:02:21.655 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 4 2015-08-03 11:02:21.657 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 5 2015-08-03 11:02:21.659 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 6 2015-08-03 11:02:21.662 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 7 2015-08-03 11:02:21.664 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 8 2015-08-03 11:02:21.666 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 9 2015-08-03 11:02:21.669 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 10 2015-08-03 11:02:21.671 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 11 2015-08-03 11:02:21.990 TableViewSample[324:90811] 结束显示单元 长度 = 2,路径 = 0 - 0 2015-08-03 11:02:21.991 TableViewSample[324:90811] 是否结束显示单元 长度 = 2,路径 = 0 - 1 2015-08-03 11:02:21.992 TableViewSample[324:90811] 结束显示单元 长度 = 2,路径 = 0 - 2 2015-08-03 11:02:21.992 TableViewSample[324:90811] 是否结束显示单元 长度 = 2,路径 = 0 - 3 2015-08-03 11:02:21.993 TableViewSample[324:90811] 结束显示单元 长度 = 2,路径 = 0 - 4 2015-08-03 11:02:21.994 TableViewSample [324:90811] 是否结束显示单元长度 = 2,路径 = 0 - 5 2015-08-03 11:02:21.994 TableViewSample [324:90811] 是否结束显示单元长度 = 2,路径 = 0 - 6 2015-08-03 11:02:21.995 TableViewSample[324:90811] 是否结束显示单元 长度 = 2,路径 = 0 - 7 2015-08-03 11:02:21.995 TableViewSample[324:90811] 是否结束显示单元 长度 = 2,路径 = 0 - 8 2015-08-03 11:02:21.996 TableViewSample[324:90811] 是否结束显示单元 长度 = 2,路径 = 0 - 9 2015-08-03 11:02:21.997 TableViewSample[324:90811] 结束显示单元 长度 = 2,路径 = 0 - 10 2015-08-03 11:02:21.997 TableViewSample[324:90811] 是否结束显示单元 长度 = 2,路径 = 0 - 11 重新加载行 2015-08-03 11:03:00.012 TableViewSample [324:90811] 是否突出显示单元格 长度 = 2,路径 = 0 - 3 2015-08-03 11:03:00.015 TableViewSample [324:90811] 选择单元格 长度 = 2,路径 = 0 - 3 2015-08-03 11:03:00.907 TableViewSample [324:90811] 询问 TableView 中的节数 2015-08-03 11:03:00.908 TableViewSample[324:90811] 询问 TableView 中的节数 2015-08-03 11:03:00.909 TableViewSample [324:90811] 询问部分中的行数 2015-08-03 11:03:00.910 TableViewSample[324:90811] 将显示单元格 长度 = 2,路径 = 0 - 3 2015-08-03 11:03:01.217 TableViewSample[324:90811] 是否结束显示单元长度 = 2,路径 = 0 - 3

所以,从日志中: [UITableView reloadData] 消耗 16ms。 [UITableView reloadSections:withRowAnimation:] 消耗 323ms。 [UITableView reloadRowsAtIndexPaths:withRowAnimation:] 消耗 302ms。

问题:

为什么即使只有一个部分,[UITableView reloadData] 也比 reloadingSections 更有效? 为什么重新加载RowsAtIndexPaths 需要这么多时间,实际上是什么时间? 什么样的工具可以帮助我验证或调试类似的问题?和帮助链接参考(如果有)? 谢谢。

【问题讨论】:

reloadData 不必(可选)为单个单元格的重新加载设置动画。 (我注意到您实际上并没有向我们展示任何代码。) @HotLicks,对不起,我尝试正确格式化代码,但没有运气。您可以在尝试“编辑”时检查我的源代码吗?非常感谢。 选择代码并点击按钮。这不是火箭科学。 答案是因为reloadData 没有任何动画,不像reloadSections:withRowAnimationreloadRowsAtIndexPaths:withRowAnimation 在重新加载tableView 的行/单元格之前验证你的动画,这也适用于collectionView。 【参考方案1】:

here,苹果说:

重新加载一行会导致表格视图向其数据源询问该行的新单元格。该表格将新单元格动画化,同时将旧行动画化。

看来,当您调用reloadrowsatindexpaths 时,将为动画初始化一个新的单元格,而我们已经知道的reloadData 将重用之前的单元格。

我认为它可以解释这个问题。

【讨论】:

以上是关于UITableView reloadData、reloadSections:withRowAnimation: 和 reloadRowsAtIndexPaths:withRowAnimation: 的的主要内容,如果未能解决你的问题,请参考以下文章

UITableView.reloadData() 没有刷新 tableView。没有错误信息

UITableView 的 reloadData() 的替代方案?

UIView 与 UITableview 和 UIImageview,使用 reloadData 访问 UITableview

UITableView 强制 sectionIndex 更新而不调用 reloadData

iOS UITableView reloadData 刷新结束后执行后续操作

调用 reloadData 时 UITableView 有不需要的动画