整理在iOS App开发中性能优化的几个思路。
iOS App性能优化专题
初级
1.手动构建UI
尽量避免使用XIB和Storyboard,这两个东西后期维护更改和性能都不行。
2.将非UI的耗时操作放在后台线程处理
在iOS APP中,对UI的相关操作只能在主线程中处理,然而当主线程的任务过多时自然会造成CPU的大量负担,从而造成卡顿。诸如数据处理、计算、文件读取等任务就可以派发到子线程中执行,当然涉及到数据时要考虑是否存在多个线程造成的数据竞赛问题。同时在将任务派发到子线程时也要考虑是否会造成死锁问题。
3.缓存
在一个APP中,可滑动的View一般都会占很大比重,而在这些如UITableView、UICollectionView的控件中,我们可以提前计算好cell的高度以及需要加载的内容并缓存起来,将计算时间提前,减少在加载或者滑动时造成的卡顿。另外,虽然无法在后台线程操作UIImageView,但我们可以在子线程先从网络或本地获取到图片的data,并在合适的时间交给主线程渲染到屏幕上。
4.减少过多的图层混合
当只有一个图层时,显示屏只需要渲染出一个图层的内容,而当有多个图层,且当最顶层的图层背景颜色不是完全不透明时,GPU需要取出至少两个图层的数据并且将他们的颜色混合,再渲染到屏幕上。
5.适当使用shouldRasterize
适当地使用光栅化后layer会被光栅化为bitmap,可以减少使用时的代价。然而修改已光栅化的数据会造成离屏渲染,所以要适当地使用光栅化。
中级
1.此时规避了一些常见的问题后,主要的性能瓶颈来到了离屏渲染
GPU在渲染屏幕要显示的内容时,会在当前屏幕的缓存区中渲染内容,然而当遇到当前缓存区无法渲染的情况时,就会开辟另一个缓存区进行渲染,渲染完毕后再将数据交给主缓存区,然而,缓存区之间的切换会比较影响性能。
2.主要的解决办法是通过如Instrument等工具找出离屏渲染的地方,并修改。
高级
1.异步渲染
由于不管我们在初级和中级中怎样优化我们的代码,最终我们的UI都是交给主线程来渲染的。而主线程是有他的性能瓶颈的,当需要渲染的UI过于复杂,超过了主线程在16.7ms里能渲染完毕的数据时,必然会出现卡顿。那么此时异步渲染就有了他的用武之地。
2.如何实现异步绘制
异步绘制的原理是在子线程中手动提前绘制好需要显示的内容,再切换到主线程将已经绘制好的内容交给主线程对应UIView里的Layer的content,从而减少主线程的UI绘制压力。
3.异步绘制的问题
然而,Apple在最开始设计UIKit时,将UI的操作和绘制限制在主线程中是有原因的。
在iOS App中,图像绘制的技术栈如下图
渲染管线如下图
可以看到,在iOS App中一帧图像从渲染到显示到屏幕上,需要CPU和GPU的共同协作。App在提交了要渲染的数据后,先由Core Graphics,Core Animation,Core Image三大绘图框架在CPU上进行一部分的先行处理后,交给底层绘图引擎OpenGL或者Metal,绘图引擎在绘制后再将数据交给GPU渲染,并光栅化后显示到我们的屏幕上。而这些,需要在16.7ms的时间中完成,才能实现我们的APP在使用时的不卡顿。
当我们在主线程上进行这些所有的操作时,可以看到UI的绘制流程是一环扣一环的,虽然在绘制的UI图像过于复杂时会给主线程造成较大压力,但不会造成图像撕裂等问题。
然而,当我们把绘制的任务放在子线程进行时,此时如果我们使用异步绘制的tableview快速滑动,而后台线程还没有将数据渲染出来,那么此时屏幕则会显示空白,如果我们要等待后台线程将UI渲染出来,这时又仍然会造成UI卡顿,甚至在极端情况还会造成UI错位的情况,那么我们就面临着一个问题:异步绘制一定优于默认的主线程绘制吗?
写在最后
目前,如Texture等异步绘制的第三方框架已经发展了很久,在性能和稳定性之间逐渐达到了一个可以令人接受的平衡,使用他们进行异步绘制的开发可以节省开发者的开发时间和调优时间。异步绘制目前来说是一个操作门槛比较高,但效果比较好的性能优化方向,值得学习和研究。同时也可以加深对iOS系统中图像渲染管线的理解