iOS UITableView到底怎么了?

Home / iOS MrLee 2015-12-8 2903

前言:笔者从事iOS开发已有三年,和大多数iOS开发者一样,到了三年,总是有一种感觉那就是iOS开发不过如此,然而笔者并未停留在这种自我陶醉的感觉之中,笔者没有追随时代的大潮去研究新的开发技巧以及新的语言(swift,笔者从来都不觉得语言是开发的障碍,反而觉得开发的思想尤为关键)。
笔者利用上班之余的时间琢磨着写了一套通用开发框架,地址是:https://github.com/h0medev/Universalapp,主要目的还是将平时的一些想法记录在案,为自己和他人提供些便利。
好了,言归正传,UITableView到底怎么了?
笔者做了个实验,用UITableView去加载1000条NSDictionary的数据,cell采用xib资源的方式布局并且将其重用(reuse),主要代码如下:

#pragma mark - UITableViewDelegate & UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 1000;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
    return cell.sizeHeight;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    LastListItemCell *cell = [tableView dequeueReusableCellWithIdentifier:@"LastListItemCell"];
    if (cell == nil) {
        registerCellNibName(@"LastListItemCell");
        cell = [tableView dequeueReusableCellWithIdentifier:@"LastListItemCell"];
    }
    NSDictionary *dict = nil;
    NSInteger rowValue = indexPath.row % 3;
    if (rowValue == 0) {
      dict = @{@"title":@"这是一段短文本",@"content":@"这是一段短文本"};
    } else if (rowValue == 1) {
      dict = @{@"title":@"这是一段中文本",@"content":@"这是一段中文本,这是一段中文本,这是一段中文本,这是一段中文本,这是一段中文本,这是一段中文本"};
    } else if (rowValue == 2) {
      dict = @{@"title":@"这是一段长文本",@"content":@"这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本,这是一段长文本"};
    }
    [cell setCellData:dict];
    NSLog(@"Load UITableViewCell %@", @(indexPath.row));
    return cell;
}

从代码里看,这里采用了自动计算高度的直接的方式,根据cell的实际高度来配置heightForRowAtIndexPath
这里加载时间竟然花了大约5s! 日志显示加载了(3 * 1000 + 5 * 2)次cell ! 在加载完毕以后,轻轻滑动tableView,然后就很有规律的做了一下两件事:
1、heightForRowAtIndexPath
2、cellForRowAtIndexPath
这里就可以解释为什么要乘以2了。
这个有什么坑?首先在加载的时候为何会被加载了3 * 1000次?会不会是因为采用了由cell来计算高度导致了多余的日志输出?
笔者调整了策略,将log放到了heightForRowAtIndexPath,注释掉了cellForRowAtIndexPath中的日志输出,依旧看到了3*1000次!这个就说明如果你的数据由n条,那么很有可能heightForRowAtIndexPath被执行了3 * n次... 笔者不禁要问,为什么要乘以3?难道UITableView健忘(重要的事情要说三次?!),不得不承认此举无疑降低了效率,此乃一坑!
效率低下也罢,加载完之后,滑动体验还是不错的,依旧很流畅,然而这还没完...
随着不断加速的滑动,越接近最后一条数据的时候,笔者发现内存居然在增加!你没听错,内存在增加!!!当笔者快速滑到底部的时候,很有意思的事情发生了,内存居然暴涨到170MB左右!
笔者不禁又要问?不就是那么点文本数据么?还重用了xib资源,为什么到了惊人170MB!
这里笔者也想知道为什么,恐怕只有iOS SDK的开发人员能解答了...
这才是大坑!慎重!慎重!慎重!(重要的事情要说三遍)...
关于UListView
UListView是笔者写的一个仿UITableView的控件,目前支持横向和纵向布局,这点比UITableView强一点,另外,UListView目前尚未引入UITableView的section等相关概念。UListView主要是笔者研究cell的重用而写的一个控件,写着写着就有点像UITableView了。自然,写好之后无疑要做测试和对比的,在对比过程中就发现了UITableView的坑,同时也显现了UListView的神奇!
优点在哪?
1、UListView完全是精简各种流程,只在必要的时候才会去加载delegate和dataSource的数据,那么这里可以确保高效,免去了UITableView 3*n的烦恼(UListView只加载1 * n次);
2、在滑动过程中只会去按需加载cell,而不会再次去加载height;
3、高速滑动下,最高CPU占用率要比UITableView低20%左右;
4、在整个滑动过程中,内存表现的很平稳,没有大的数值波动,明显优于UITableView;
5、支持横向布局,而UITableView目前仅支持纵向;
缺点?
到目前为止,UListView尚还不完全具备UITableView的一些功能,如前面提到的section、header、footer等等,不过后续会逐步完善。
上述源码可见于我的开源框架:https://github.com/h0medev/Universalapp
框架依旧在更新,欢迎关注!
以上内容纯属个人遇到的问题和相应的看法,不建议人人亦云,建议大家亲自动手,眼见为实!
本文转自:http://www.cnblogs.com/h0medev/p/5028436.html

本文链接:https://www.it72.com/7130.htm

推荐阅读
最新回复 (0)
返回