iOS进阶干货分享

iOS性能优化系列篇之“列表流畅度优化”

2019-05-28  本文已影响42人  _小迷糊_997

原文作者:Hello_Vincent
原文地址:https://juejin.im/post/5b72aaf46fb9a009764bbb6a#heading-1

这一篇文章是iOS性能优化系列文章的的第二篇,主要内容是关于列表流畅度的优化。在具体内容的阐述过程中会结合性能优化的总体原则进行阐述,所以建议大家在阅读这篇文章前先阅读一下上一篇文章:iOS性能优化系列篇之“优化总体原则”

由于平时工作比较忙,两篇之间的间隔有点久。但这两篇文章出乎我意料地受到了大家的喜欢,所以我希望后面有时间能把这个系列更新下去,下一步准备写一篇关于iOS内存相关的优化文章。也希望这篇列表流畅度优化的文章能够给大家带来一点点启示。

和上一篇综述性质的文章不同,这一篇文章工程实用性更强一些,更多的是一些优化技术细节。文中讨论了许多可能影响列表流畅度的因素,由于2018 WWDC里面讲述了大量的关于性能优化相关的内容,因此本文也在相关的内容里面加入2018 WWDC的性能优化部分。

读者可将本体提及的优化手段或者原理应用到自己的项目中去。但是希望大家在优化过程中,要结合自己的项目具体问题具体分析,因为本文讨论的影响流畅度的因素,可能并不是你的应用流畅性不佳的瓶颈,根据我的经验,大部分流畅的问题都是业务逻辑导致的,反倒什么离屏渲染啊之类大家耳熟能详的流畅度的影响因素在实际项目中并没有想象的那么大。如果不经实地测量就盲目应用一些优化手段,可能会导致过度优化,事倍功半。

卡顿产生的原因

在总体原则篇中提到,五大原则中的其中一个就是要理解优化任务的底层运行机制,因为只有深入了解底层机制才能更好的有针对性的提出更优的解决方案,所以在进行列表流畅度优化前,我们一定要弄清楚一个view从创建到显示到屏幕上都经历了那些过程,在这些过程中那些方面可能会导致性能瓶颈,以及造成卡顿的底层原因是什么。

我们知道iOS设备大部分情况下,屏幕刷新频率是60hz(ProMotion下是120hz),也就是每隔16.67ms会进行一次屏幕刷新。每次刷新时,需要CPU和GPU配合完成一次图像显示。其主要流程如下:

应用内:

应用外(render server):

从上面的图中可以看到,在view显示的过程中,CPU和GPU都各自承担了不同的任务,CPU和GPU不论哪个阻碍了显示流程,都会造成掉帧现象。所以优化方法也需要分别对CPU和GPU压力进行评估和优化,在CPU和GPU压力之间找到性能最优的平衡点, 无论过度优化哪一方导致另一方压力过大都会造成整体FPS性能的下降。而寻找平衡点的过程则因项目特点不同而不同,并没有一套通用的方法,需要我们用instrument等性能评测工具,根据实际app的性能度量结果去做优化,不能凭空乱猜。

CPU优化

我们先看table view在滑动过程中CPU占用的情况。

从上图可以看出,在滑动过程中CPU占用特点是:

根据上述特点我们可以做如下优化:

预加载,空间换时间

为什么要预加载:

通过预加载我们希望达到的CPU理想占用效果如下:


预加载内容:

静态资源预加载

动态资源预加载

WWDC 2018中讲到了一个iOS12的底层优化点,苹果工程师在性能调优的时候发现一个导致丢帧的奇怪case,在没有其他后台线程运行、只有滑动的情况下,会比有少量的后台线程的情况更容易掉帧。通过调研CPU的调度算法发现,在仅有滑动的情况下,为了省电,CPU占用会保持比较底,但是这样CPU会花更多的时间来计算,就会导致可能错过这一帧。所以iOS12中,会把UIKit框架上所有的信息(滑动信息以及滑动frame的关键时间点)传递给底层CPU性能控制器,这样CPU可以更智能调度以在frame截止的时机内完成CPU计算。这部分属于系统底层的优化,对于应用开发者只要应用运行在iOS12就可以获得这部分优化。

多线程

为什么要多线程:

最终通过多线程,我们希望CPU占用达到如下效果:

使用多线程注意事项:

可在子线程中进行的任务

缓存

缓存的内容可以是

更优的实现方式

这里说的更优的实现方式,主要是指为了实现同一功能或者效果,CPU占用更小的实现方式。这部分包括的内容其实非常多,也很杂。受限于篇幅和水平有限,这里笔者仅罗列一些比较常见的点,并针对其中比较重要的drawRect优化和图片优化内容做进一步的讲解。

下面详细讲下drawRect优化和图片优化

drawRect优化

图片优化

在大多数app中,图片绝对是使用最频繁的资源之一,我们知道磁盘和网络的加载速度和内存比要慢很多,而一般图片都比较大,I/O十分耗时。而且图片还涉及解码,也是一项十分消耗CPU的工作,因此图片的优化对app的性能有着十分关键的作用。谈谈iOS中图片的解压缩

在之前将的优化总体原则的时候,我们说过需要理解优化对象的运行机制,我们先了解下图片显示原理:

针对上面的过程,我们的优化手段主要有:

GPU优化

CPU和GPU之所以大不相同,是由于其设计目标的不同,它们分别针对了两种不同的应用场景。CPU需要很强的通用性来处理各种不同的数据类型,同时又要逻辑判断又会引入大量的分支跳转和中断的处理。这些都使得CPU的内部结构异常复杂。而GPU面对的则是类型高度统一的、相互无依赖的大规模数据和不需要被打断的纯净的计算环境。所以CPU擅长逻辑控制,串行的运算。和通用类型数据运算不同,GPU擅长的是大规模并发计算,这也正是密码破解等所需要的。所以GPU除了图像处理,也越来越多的参与到计算当中来。参考

iOS中GPU在显示方面的工作主要是:接收提交的纹理(Texture)和顶点描述(三角形),进行变换(transform)、混合并渲染,然后输出到屏幕上。屏幕上的内容,主要也就是纹理(图片)和形状(三角模拟的矢量图形)两类。一般来说,CALayer的大多数属性都是使用GPU来绘制的。虽然GPU在处理图像等渲染是速度很快,但如果开发过程中使用不当,仍会导致GPU占用过高,渲染速度跟不上屏幕刷新导致卡顿。

对GPU消耗比较高的操作有:

常用优化手段

优化工具

iOS开发中,在GPU优化上,我们一般使用instruments中的Core Animation工具来进行滑动流畅度优化,在Core Animation中我们可也看到列表滑动过程中的FPS,其中有一些很有用的debug选项,帮助我们找到代码中有性能问题的代码。下面是一些常用的选项:

避免Offscreen-Rendered的方式可以其他方式实现圆角、shadow + shadowPath等。

总结

本文的讲了一些造成卡顿的原因,以及CPU和GPU优化的常用技巧和工具,大家在优化的时候可以作为参考。但不要把优化手段局限在这些方面,不同的应用有各自不同的特点,一定要具体问题具体分析。甚至可以跳出技术范畴,在交互方面做一些文章,比如在减少列表每次从服务器获取的数据数量、采用用户手动点击触发获取更多数据而不是滑动过程中自动获取、使用交互动画等都可以极大改善用户的滑动体验。

最后还是要强调一下我上一篇文章讲的优化时候需要注意的几大原则,这样才能在优化过程中有更好的全局观,尽量少走弯路,希望大家能够在优化过程中时刻牢记。

上一篇 下一篇

猜你喜欢

热点阅读