zoukankan      html  css  js  c++  java
  • UITableView优化

    UITableView优化


    重用

    UITableView最核心的思想就是UITableViewCell的重用机制。当TableView需要显示一个Cell时,会先从已创建的Cell中找一个可以重用的,然后展现到屏幕。一般情况下,可以被重用的Cell都滚到了屏幕区域外。如果慢慢地拖动TableView,就可以看到Cell不断地被重用(通过断点可以看到Cell的init或awakeFromNib没有被调用)。但是如果快速滚动,还是可能会看到Cell被创建。UITableView只会创建一屏幕(或一屏幕多一点)的UITableViewCell,其他都是从中取出来重用的。

    已经在StoryBoard的TableView中定义Cell的ProtoType

    	则指定其ReuseIdentify,在delegate返回Cell的时候,调用:
    	[tableView dequeueReusableCellWithIdentifier:kCellID];
    

    Cell是从单独的xib加载

    	则需要先注册:
    	[tableView registerNib:[UINib nibWithNibName:kCellID bundle:nil] forCellReuseIdentifier:kCellID];
    

    Cell的ProtoType个数尽可能少,因为Cell的种类越多,TableView创建的Cell个数就越多,并且是成倍增长。


    缓存

    缓存基本上可以解决大部分性能问题。TableView需要知道Cell的高度,才能对Cell进行布局;需要知道所有的Cell的高度,才能知道TableView本身的高度,所以,每次调用reloadData,都需要计算所有Cell的高度。我们要尽量减小高度计算的复杂度。
    

    缓存Cell的高度

    UITableView最主要的两个回调方法是tableView:cellForRowAtIndexPath:tableView:heightForRowAtIndexPath:

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

    所以 heightForRowAtIndexPath:是调用最频繁的方法。

    思路是把赋值和计算布局分离。这样让tableView:cellForRowAtIndexPath:方法只负责赋值,tableView:heightForRowAtIndexPath:方法只负责计算高度。尽量不将Cell的实例放入 tableView:heightForRowAtIndexPath: 中。

    高度固定、类型单一的Cell
    	在创建TableView的时候,直接设置其rowHeight属性。
    
    对于高度固定、类型多样的Cell
    	实现代理方法,根据Cell的类型返回不同的高度:
    	比如 ACell 都是50;BCell都是80 之类的。
    		- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    
    对于高度不固定的Cell
    	由于需要动态计算高度,所以运算量必然会增大,但是还是存在优化的空间。常见的优化方式是,把cellHeight作为data的一个属性缓存起来,对于每一个data对应的每一个cell,就只需要计算一次高度。		
    	当然,这样的方式,还是把运算量放到了TableView的代理方法内,其实也可以在创建ContentInfo本身的时候,就调用它的calcHeight方法,在代理方法里就可以可以直接返回info.cellHeight了。但也要结合实际情况进行取舍,因为有时候,有了数据源,但不一定需要展示TableView,提前计算高度反而会浪费时间。
    

    缓存Cell的资源

    比如每一个Cell都需要用到的UIImage,UIFont,NSDateFormatter或者任何在绘制时需要的对象,推荐使用类层级的初始化方法中执行分配,并将其存储为静态变量。也可以缓存整个View。
    

    创建

    去掉AutoLayout

    如果发现通过StoryBoard+xib+AutoLayout创建Cell时性能满足不了需求,可以考虑去掉AutoLayout。
    

    代码创建Cell

    如果不用AutoLayout还是有问题,可以考虑通过代码创建Cell的Views。
    

    自绘

    如果使用代码创建还是解决不了问题,那就只能靠自绘了,重载Cell的drawRect方法即可。
    因为Cell上添加系统控件的时候,实质上系统都需要调用底层的接口进行绘制,当我们大量添加控件时,对资源的开销也会很大,所以我们可以索性直接绘制,提高效率。
    如果在重写drawRect方法就不需要用GCD异步线程了,因为drawRect本来就是异步绘制的。对于图文混排的绘制,可以移步Google,研究下CoreText,这块内容太多了,不便展开。
    

    按序加载

    如果目标行与当前行相差超过指定行数,只在目标滚动范围的前后指定10行加载。
    可以在UIScrollView的代理 scrollViewWillEndDragging中判断 行数与指定行的差距,若差距超过一定值,就不显示Cell。
    这个在大量图片展示,网络加载的时候很管用,可以配合SDWebImage异步加载。	
    

    渲染

    减少子View的个数和层级

    子View的层级越深,渲染到屏幕上所需要的计算量就越大。
    

    减少子View的透明图层

    对于不透明的View,设置opaque为YES,这样在绘制该View时,就不需要考虑被View覆盖的其他内容,避免GPU对Cell下面的内容也进行绘制。
    

    避免CAlayer特效。

    给Cell中View加阴影会引起性能问题,如下面代码会导致滚动时有明显的卡顿:

    view.layer.shadowColor = color.CGColor;
    view.layer.shadowOffset = offset;
    view.layer.shadowOpacity = 1;
    view.layer.shadowRadius = radius;	
    

    可以尝试用 shadowPath创建阴影。

    图片

    尽量显示“大小刚好合适”的图片资源。避免大量的图片缩放、颜色渐变等。
    

    • 类似微信朋友圈这种就可以只定义一个cell
    • 善用hidden隐藏(显示)Subview,来显示不同类型的内容
    • 然后提前计算并缓存每个Cell的高度,在Model(Entity)中计算并保存Cell的高度

    更多可以参考 http://blog.sunnyxx.com/2015/05/17/cell-height-calculation/

  • 相关阅读:
    POJ 1015 Jury Compromise【DP】
    POJ 1661 Help Jimmy【DP】
    HDU 1074 Doing Homework【状态压缩DP】
    HDU 1024 Max Sum Plus Plus【DP,最大m子段和】
    占坑补题。。最近占的坑有点多。。。
    Codeforces 659F Polycarp and Hay【BFS】
    Codeforces 659E New Reform【DFS】
    Codeforces 659D Bicycle Race【计算几何】
    廖大python实战项目第四天
    廖大python实战项目第三天
  • 原文地址:https://www.cnblogs.com/sunyanyan/p/5139228.html
Copyright © 2011-2022 走看看