UITableView——reloadData与reloadSection性能比较

原文:http://blog.csdn.net/iosswift/article/details/50001145

周五上午,测试,有bug:每次reset模拟器后,第一次进入界面,闪退,第二次进入界面,结果正常。
以下是这个bug的错误日志:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 1. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).’

发现刷新列表时,闪退。问题出在:[self.tableViewreloadSections:[NSIndexSetindexSetWithIndex:2]withRowAnimation:UITableViewRowAnimationNone];
这个方法我没用过,从方法名看出,这个方法是局部刷新列表的某个section。但一般我都是用reloadData,刷新整个列表。于是,我把reloadSection改回reloadData,发现这个两个bug都不再出现了。
按道理,使用reloadSection应该没有问题啊,但为什么这里不能使用reloadSection呢?
其实,仔细看错误日志就明白,问题出在该section的row是动态变化的。

那么,问题来了,为什么要把reloadData改成reloadSection呢?
应该是因为reloadSection效率更高,速度更快?
但真的是这样吗?我想验证一下。
好吧,我承认我是有多无聊?闲的蛋疼……

新建一个test工程,创建一个tableview,3个section,每个section有30行。这个tableview总共有90行数据。
代码如下:

**[objc]** [view plain](http://blog.csdn.net/iosswift/article/details/50001145#) [copy](http://blog.csdn.net/iosswift/article/details/50001145#)

- (void)viewDidLoad {  
    [super viewDidLoad];  
    self.tableview.delegate = self;  
    self.tableview.dataSource = self;  
      
//    NSLog(@"start");  
//    for(int i=0;i<1000000;i++){  
//        [self.tableview reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationNone];  
//    }  
//    NSLog(@"end");  
      
    NSLog(@"start");  
    for(int i=0;i<1000000;i++){  
        [self.tableview reloadData];  
    }  
    NSLog(@"end");  
      
      
}  
  
- (void)didReceiveMemoryWarning {  
    [super didReceiveMemoryWarning];  
    // Dispose of any resources that can be recreated.  
}  
  
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{  
    return 3;  
}  
  
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{  
    return 30;  
}  
  
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{  
    UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"cell"];  
    cell.textLabel.text = [NSString stringWithFormat:@"section:%li,row:%li",(long)indexPath.section,(long)indexPath.row];  
    for(int i=0;i<1000;i++){  
        int y = indexPath.row+indexPath.section;  
    }  
    UIImageView *image = [[UIImageView alloc] initWithFrame:CGRectMake(200, 5, 90, 75)];  
    image.image = [UIImage imageNamed:@"254"];  
    [cell addSubview:image];  
    return cell;  
}  

在iPhone 6 plus模拟器下做了三组对照试验,试验结果如下:
在每个cell只有一个label的情况下,分别用reloadSection,reloadData方法刷新列表,10次,100次,1000次,10000次,100000次,1000000次时,时间、CPU、内存的比较:



每个cell有一个label和一张图片,比较



每个cell有一个label、一张图片和执行1000次的for循环,比较

每个cell有一个label、一张图片和执行1000次的for循环,reloadSection,reloadData,在执行10次~1000000次花费时间对数表(前两种情况就不列图表了,和最后情况类似)


reloadSection,reloadData,在执行10次~1000000次花费内存对数表

从这些实验数据发现:在10000次以内,reloadSection和reloadData两者在时间、CPU、内存相差并不大,甚至在某些情况,reloadData性能要优于reloadSection。大于10000次以后,reloadSection的性能高于reloadData。
而我们实际的项目中几乎不会刷新某个列表超过100次,两者性能差不多,但reloadSection不能用于row,section动态变化的情况下,所以还是更加推荐使用reloadData方法
总结:平时编码过程中,通常会根据自己的经验判断,采用某种性价比更高的方式。但事实真的是这样的吗?我们很少去想这个问题,也几乎不会去验证,因为我们觉得理所当然。套用知乎的一句名言:凡事先问是不是,再问为什么,警戒自己,不要被自己所谓的“经验”误导。

———————————————————————我是分割线———————————————————————————
之后有同事提到:

关于reloadSections vs reloadData
测试例子考虑的是数据源不变的情况下cell的重绘制
但复杂场景,之所以考虑部分刷新reloadSections,是因为刷新每个section,cell不单单是cell的绘制,也都有包含I/O和运算操作
而这个时候 reloadData会触发其他不必要的运算和I/O

tableview的主要作用是展示数据,而I/O操作其实不适合放在cell中。
包括图片的下载其实不宜放在cell中,这会导致界面卡顿。
更好的方法是:将获取数据源的代码放到次要线程中,这样主线程才能更好的加载视图。
我们常用的MVC,MVVM架构也就是为了将业务逻辑与视图尽量剥离,让UI更好的展示数据。

至于运算操作,在第三种情况中,我加了一个执行一千次的for循环来模拟复杂的运算。
reloadData相比reloadSection,前者执行运算操作的次数是后者的三倍。
在这种情况下,两者的性能在100000次以内,依然相差无几。

而在数据源动态变化的情况下,例如在某些页面中,每个Section中的row是动态变化的,单独使用reloadSection会导致文中的bug。而使用reloadData不会出现这个bug。

而reloadSection相比reloadData多一点的是,在刷新的时候有动画。
更多情况下,是搭配beginUpdates和endUpdates来实现 deleteSections:withRowAnimation:的功能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容