UITableView性能优化

182 阅读4分钟
原文链接: www.jianshu.com

UITableView是开发中最常用的组件,容易遇到流畅度不佳,卡顿问题.常见的UITableView优化能够提升App的整体性能,因此有必要总结一下性能优化的方法.

Cell重用

每次通过dequeueReusableCell方法进行单元格重用,而不是每次创建新的Cell.

let cell = tableView.dequeueReusableCell(withIdentifier: "FlyElephantCell", for: indexPath) as! FlyElephantCell

Cell高度

Cell高度分为两种情况,分为固定高度和动态高度。一般情况下Cell能固定就固定,可以统一高度,通过隐藏SubView的形式显示Cell.

动态高度在iOS8之后通过autolayout和设置rowHeight为UITableViewAutomaticDimension来实现。

tableView.estimatedRowHeight = 60
        tableView.rowHeight = UITableViewAutomaticDimension

如果不通过此种形式,可以缓存每个单元格高度,避免重复计算.

不透明

避免设置透明的单元格或子视图。半透明或透明元素(alpha低于1.0)的视图,很好看,但是会有消耗GPU资源,造成性能损失.

默认外观

当用户快速滑动列表时,如果发现丢帧的现象,可以考虑默认外观。当滑动速度降低的时候,低于设置的阈值时,刷新最终的视图并填充数据.

CPU & GPU

在view显示的过程中,CPU和GPU都各自承担了不同的任务,CPU和GPU不论哪个阻碍了显示流程,都会造成掉帧现象.所以优化方法也需要分别对CPU和GPU压力进行评估和优化,在CPU和GPU压力之间找到性能最优的平衡点, 无论过度优化哪一方导致另一方压力过大都会造成整体FPS性能的下降.

CPU 主要执行的任务:

  • 对象创建,可以使用CALayer替换UIView.
  • 对象调整,尽量减少不必要的属性修改.
  • 对象销毁,在后台线程销毁对象.
  • 布局计算,视图布局的计算是 App 中最为常见的消耗 CPU 资源的地方。如果能在后台线程提前计算好视图布局、并且对视图布局进行缓存,那么这个地方基本就不会产生性能问题了.
    *Autolayout,在大部分情况下Autolayout能很好的提升开发效率,但是 Autolayout 对于复杂视图来说常常会产生严重的性能问题.
  • 文本计算,如果用 CoreText 绘制文本,那就可以先生成 CoreText 排版对象,然后自己计算了,并且 CoreText 对象还能保留以供稍后绘制使用.
  • 文本渲染,自定义文本控件,用 TextKit 或最底层的 CoreText 对文本异步绘制.
  • 图片解码,后台线程先把图片绘制到 CGBitmapContext 中,然后从 Bitmap 直接创建图片.
  • 图片绘制,图像的绘制通常是指用那些以 CG 开头的方法把图像绘制到画布中,然后从画布创建图片并显示这样一个过程.由于 CoreGraphic 方法通常都是线程安全的,所以图像的绘制可以很容易的放到后台线程进行.

GPU 主要执行的任务:

  • 纹理的渲染,所有的 Bitmap,包括图片、文本、栅格化的内容,最终都要由内存提交到显存,绑定为 GPU Texture。不论是提交到显存的过程,还是 GPU 调整和渲染 Texture 的过程,都要消耗不少 GPU 资源.当图片过大,超过 GPU 的最大纹理尺寸时,图片需要先由 CPU 进行预处理,这对 CPU 和 GPU 都会带来额外的资源消耗.
  • 视图的混合 (Composing),当多个视图(或者说 CALayer)重叠在一起显示时,GPU 会首先把他们混合到一起。如果视图结构过于复杂,混合的过程也会消耗很多 GPU 资源。为了减轻这种情况的 GPU 消耗,应用应当尽量减少视图数量和层次,并在不透明的视图里标明 opaque 属性以避免无用的 Alpha 通道合成.
  • 图形的生成,CALayer 的 border、圆角、阴影、遮罩(mask),CASharpLayer 的矢量图形显示,通常会触发离屏渲染(offscreen rendering),而离屏渲染通常发生在 GPU 中。当一个列表视图中出现大量圆角的 CALayer,并且快速滑动时,可以观察到 GPU 资源已经占满,而 CPU 资源消耗很少。这时界面仍然能正常滑动,但平均帧数会降到很低。为了避免这种情况,可以尝试开启 CALayer.shouldRasterize 属性,但这会把原本离屏渲染的操作转嫁到 CPU 上去。对于只需要圆角的某些场合,也可以用一张已经绘制好的圆角图片覆盖到原本视图上面来模拟相同的视觉效果。最彻底的解决办法,就是把需要显示的图形在后台线程绘制为图片,避免使用圆角、阴影、遮罩等属性.

参考链接

iOS 保持界面流畅的技巧
UITableView 的完美平滑滚动