tableview优化技巧

来源:互联网 发布:linux jdk下载 64位 编辑:程序博客网 时间:2024/06/05 01:00

14年底的时候, 做过一个类似朋友圈的功能, 后续对他做过一些优化, 时过两年之久, 心血来潮, 想写一篇关于tableview优化的为文章, 以此纪念过往的优化史.

和UICollectionView是iOS开发中用的最多且最重要的控件之一. 对于这块的优化几乎就可以决定App的运行流畅度和性能.


一. 重用机制

UITableView只会在开始的时候创建一屏或一屏多点的UITableViewCell, 其他的都是使用Identifier从重用池中取出来的,重用池实际上就是一个数组. 每当我们滑动UITableViewCell的时候, 划出屏幕的部分系统会自动把他放到重用池中, 需要显示的再从重用池中取出. 这样的做法减少了cell等很多控件的创建, 极大的节省了软件和硬件的开销. 

在重用的过程中有一种比较特殊(开发中经常会出现)的方式是一个UITableView中很多种的cell, 如果在开始的时候没有用到这种cell, 后面用到的时候去重用池中取的时候就会找不到这种重用标记, 这个时候他就会使用新的标记重新创建一个cell.

清楚了基本的重用原理之后, 我们继续来看看UITableView的回调方法.回调方法中用的最多的两个方法就是:- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath. 布局控件的时候系统先调用heightForRowAtIndexPath获取到cell的高度,然后才会使用cellForRowAtIndexPath创建一个cell, 如果我们有100个cell, 当前屏幕上只显示了两个, 那开始就会调用100次heightForRowAtIndexPath, 两次cellForRowAtIndexPath. 滑动屏幕的时候,每加载一个cell都会执行一次这两个方法,这个地方大家可能隐约会发现有疑问
1. 调用顺序和我们想的不太一致.UITableView继承自UIScrollView,因此要首先确定contentSize及位置, 才能创建cell, 所以会首先调用heightForRowAtIndexPath方法

2. 每加载一次cell, 就会调用一次这两个方法, 严重的消耗了系统的性能. 首先这两个方法的工作内容要分开, 一个计算高度, 另一个绘制界面. 计算高度的方法里面不能出现绘制界面的代码,否则开销很大.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{

    // 这个方法里面最好这样写, 会节省很多性能

    NSDictionary *dict =datas[indexPath.row];

    float height = [dict[@"frame"]CGRectValue].size.height;

    return height;

}

一. 性能优化

1. 不要使用ClearColor,无背景色,透明度也不要设置为0

2. 不要实现无用的代理方法,tableView只遵守两个协议

3. 一定要使用纯代码

UITableView的优化主要从三个方面入手:

  • 提前计算并缓存好高度(布局),因为heightForRowAtIndexPath:是调用最频繁的方法;
  • 异步绘制,遇到复杂界面,遇到性能瓶颈时,可能就是突破口;
  • 滑动时按需(需要多少, 加载多少, 适用于滑动非常快的前提下)加载,这个在大量图片展示,网络加载的时候很管用!(SDWebImage已经实现异步加载,配合这条性能杠杠的)。
  • 除了上面最主要的三个方面外,还有很多几乎大伙都很熟知的优化点

    1. 正确使用reuseIdentifier来重用Cells
    2. 尽量使所有的view opaque,包括Cell自身
    3. 尽量少用或不用透明图层, 背景色也不要设置为ClearColor, 这样渲染耗时比较长.
    4. 如果Cell内现实的内容来自web,使用异步加载,缓存请求结果
    5. 减少cell中控件的数量, 不同风格的cell可以使用不同的重用标识符
    6. 在heightForRowAtIndexPath:中尽量不使用cellForRowAtIndexPath:,如果你需要用到它,只用一次然后缓存结果
    7. 尽量少用addView给Cell动态添加View, 要加载到contentview上, 可以初始化时就添加,然后通过hide来控制是否显示
    8. 如果只是跟新某组的话, 尽量使用reloadSection
    9. 按需加载cell, cell滚动很快时, 只加载范围内的cell
    10. 不要实现无用的代理方法, 如果高度固定的, 开始的时候设置好, 不要在代理里面返回

未完待续.......
0 0
原创粉丝点击