Performance Optimization of UITableView

来源:互联网 发布:ubuntu登录密码忘记了 编辑:程序博客网 时间:2024/05/29 09:56

UITableView核心的优化在UITableViewCell上,从UITableView最主要的两个回调方法来分析UITableView的性能优化。

  • tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
  • tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell

HeightOfRow

UITableView 是个 UIScrollView,就像平时使用 UIScrollView 一样,加载时指定 contentSize 后它才能根据自己的 bounds、contentInset、contentOffset 等属性共同决定是否可以滑动以及滚动条的长度。而 UITableView 在一开始并不知道自己会被填充多少内容,于是询问 data source 个数和创建 cell,同时询问 delegate 这些 cell 应该显示的高度,这就造成它在加载的时候浪费了多余的计算在屏幕外边的 cell 上。

UITableView的回调顺序是先多次调用tableView:heightForRowAtIndexPath:以确定contentSize及Cell的位置,然后才会调用tableView:cellForRowAtIndexPath:,从而来显示在当前屏幕的Cell。

eg. 显示100个Cell,当前屏幕显示5个。那么刷新(reload)UITableView时,UITableView会先调用100次tableView:heightForRowAtIndexPath:方法,然后调用5次tableView:cellForRowAtIndexPath:方法;滚动屏幕时,每当Cell滚入屏幕,都会调用一次tableView:heightForRowAtIndexPath:、tableView:cellForRowAtIndexPath:方法。

因此,首要任务优化 tableView:heightForRowAtIndexPath 方法。Cell 高度设定有两种方式:

 //针对所有 Cell 具有固定高度的情况 self.tableView.rowHeight = 88;
//实现 UITableViewDelegate,实现了这个方法后,rowHeight 的设置将无效 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {    return 88;}
  • cell定高时, 强烈建议使用rowHeight方式保证不必要的高度计算和调用。

  • cell变高时, 尽量提前计算并缓存好高度,把两个代理方法任务分离,不要重叠代码。
    tableView:cellForRowAtIndexPath:方法只负责赋值,tableView:heightForRowAtIndexPath:方法只负责计算高度

EstimatedRowHeight 高度估计

If the table contains variable height rows, it might be expensive to calculate all their heights when the table loads. Using estimation allows you to defer some of the cost of geometry calculation from load time to scrolling time.

self.tableView.estimatedRowHeight = 88;// or- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {    // return xxx}

面对种类不同的 cell,我们依然可以使用简单的 estimatedRowHeight 属性赋值,只要整体估算值接近就可以。

  • 设置估算高度后,contentSize.height 根据“cell估算值 x cell个数”计算,这就导致滚动条的大小处于不稳定的状态,contentSize 会随着滚动从估算高度慢慢替换成真实高度,肉眼可见滚动条突然变化甚至“跳跃”。

  • 滑动时实时计算高度带来的卡顿

iOS8 self-sizing cell

iOS8 WWDC 中推出了 self-sizing cell 的概念,旨在让 cell 自己负责自己的高度计算。

//如果不加上估算高度的设置,自动算高就失效了。rowHeight 的默认值已经设置成了 UITableViewAutomaticDimension,所以第二行代码可以省略。self.tableView.estimatedRowHeight = 213;self.tableView.rowHeight = UITableViewAutomaticDimension;
  • 只支持 iOS8 以上
  • 不开启高度估算时,UITableView 上来就要对所有 cell 调用算高来确定 contentSize
  • cell 被认为随时都可能改变高度,所以每次滑动出来后都要重新计算高度。

CellForRow

Reuse重用cell
简单的理解就是:UITableView只会创建一屏幕(或一屏幕多一点)的UITableViewCell,其他都是从中取出来重用的。每当Cell滑出屏幕时,就会放入到一个集合(或数组)中(这里就相当于一个缓冲池),当要显示某一位置的Cell时,会先去集合(或数组)中取,如果有,就直接拿来显示;如果没有,才会创建。这样做的好处可想而知,极大的减少了内存的开销。

ContacterTableCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ContacterTableCell"];    if (!cell) {        cell = (ContacterTableCell *)[[[NSBundle mainBundle] loadNibNamed:@"ContacterTableCell" owner:self options:nil] lastObject];    }

自定义Cell的绘制
我们在Cell上添加系统控件的时候,实质上系统都需要调用底层的接口进行绘制,当我们大量添加控件时,对资源的开销也会很大,所以我们可以索性直接绘制,提高效率。
重写drawRect, 异步绘制….

0 0
原创粉丝点击