UITableView的reloadData、reloadSections:withRowAnimation:和reloadRowsAtIndexPaths:withRowAnimation:的性能表现

4
我建立了一个测试应用程序,以测试重新加载表视图的这三种方法的性能。 enter image description here
//
//  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

当三个方法被调用时记录日志。

ReloadData
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.

因此,从日志中可以看出:

[UITableView reloadData]消耗了16毫秒。

[UITableView reloadSections:withRowAnimation:]消耗了323毫秒。

[UITableView reloadRowsAtIndexPaths:withRowAnimation:]消耗了302毫秒。

问题:

  • 即使只有一个section,为什么[UITableView reloadData]比重新加载sections更有效率?
  • 为什么重新加载行需要那么长时间,实际上是什么导致了这个时间?
  • 有哪些工具可以帮助我验证或调试类似的问题?是否有任何帮助链接参考?
  • 谢谢。

我注意到你实际上没有向我们展示任何代码。 - Hot Licks
@HotLicks,抱歉代码有问题,我尝试过格式化它,但没有成功。你能在尝试“编辑”时检查我的源代码吗?非常感谢。 - antonio081014
选择代码并单击“{}”按钮。这不是火箭科学。 - Hot Licks
1
答案是因为reloadData没有任何动画,不像reloadSections:withRowAnimationreloadRowsAtIndexPaths:withRowAnimation,它们在重新加载tableView的行/单元格之前验证您的动画,这也适用于collectionView。 - 0yeoj
@HotLicks,非常感谢您提供如此出色的格式化,并向我展示如何实现。 - antonio081014
显示剩余2条评论
1个回答

4
在这里,苹果提到:(点击此处)

重新加载一个行会导致表视图向它的数据源请求该行的新单元格。表视图会以将旧行动画移出的同时,将新单元格动画移入。

看起来,当您调用reloadrowsatindexpaths时,会为动画初始化一个新的单元格,而我们已经知道reloadData会重复使用之前的单元格。
我认为这可以解释这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接