界面显示原理
iOS设备默认刷新频率是60HZ,也就是两帧相隔时间是1/60秒,即大概16.7ms。在这16.7ms中,为了显示一帧,需要如下工作:
- CPU计算好各个视图的位置,大小,对图片进行解码等,绘制成纹理交给GPU
- GPU对收到的纹理进行混合,顶点变换,渲染到帧缓冲区
- 每16.7ms一个时钟信号到达,帧缓冲区取出一帧,显示到屏幕
原因
当CPU或者GPU被大量占用的时候,在16.7ms中,没有准备好下一帧的绘制,导致时钟信号到来的时候,取得还是上一帧的内容,导致界面卡顿
解决思路
尽量减少CPU和GPU的资源消耗
离屏渲染
在iOS中,渲染分为CPU和GPU渲染两种,而GPU渲染又分为GPU缓冲区和非GPU缓冲区两种
- On-Screen Rendering:当前屏幕渲染,在当前用于显示的屏幕缓冲区进行渲染操作
- Off-Screen Rendering:离屏渲染,在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作
CPU渲染(软件渲染), CPU绘制成bitmap,交给GPU
GPU渲染(硬件渲染)
GPU缓冲区渲染
非GPU缓冲区渲染(额外开辟缓冲区)
通常,CPU渲染,和GPU非帧缓冲区内渲染统称为离屏渲染。因为,CPU和帧缓冲区是为图形图像显示做了高度优化的,速度较快
什么情况下会触发离屏渲染
- layer具有圆角或阴影shadow
- drawRect中绘制
- 光栅化 layer.shouldRasterize = YES
- 用CoreGraphics的CGContext绘制的
优化
CPU层面
- 尽量使用轻量级的对象,比如用不到事件处理的地方使用CALayer代替UIView
- 提前计算好布局(如cell行高)
- 不要频繁的调用和调整UIView的相关属性,比如frame、bounds、transform等属性(UIView的显示属性实际都是CALayer的映射,而CALayer本身没有这些属性,都是初次调用时通过resolveInstanceMethod添加并创建Dictionary保存的,耗费资源)
- Autolayout比直接设置frame消耗更多CPU资源
- 图片的size最好与UIImageView的size保持一致,减少图片显示时的计算处理
- 控制线程的最大并发量
- 将耗时操作放到子线程
- 少使用addSubview给cell动态添加view
GPU层面
- 避免短时间内大量图片的显示,尽可能将多张图片合成一张进行显示
- GPU能处理的最大纹理尺寸是4096 * 4096,一旦超过这个尺寸,会占用CPU资源进行处理
- GPU会将多个视图混合在一起再去显示,混合的过程会消耗CPU资源,尽量减少视图数量和层次
- 减少透明的视图
- 尽量避免出现离屏渲染
网友评论