我想各位攻城狮们肯定听过一句话:“过早的优化是万恶之源”。若是你有着丰富的项目经验,一定会对这句话有着自己的体会,而若是编程新手,那么,请牢记这句话。在一个项目开发到后期,优化就会成为一个不可避免的话题,而这时,优化以及性能问题又显得尤为重要。
本文讨论的是iOS的图形性能问题。
1、 CALayer的shouldRasterize(光栅化)
这个属性看上去很不好理解,光栅化是将几何数据经过一系列变换后最终转换为像素,从而呈现在显示设备上的过程。光栅化的本质是坐标变换、几何离散化。
把layer的shouldRasterize设为YES后,CALayer会被光栅化为bitmap,layer的阴影等效果也会被保存到bitmap中作为缓存。在使用了shadow或cornerRadius等效果时,缓存使性能得到提升。
但是在使用这个属性前,需要明确3点:
2、Offscreen rendering(离屏渲染)
讨论造成离屏渲染的原因之前,先说明什么是离屏渲染:离屏渲染指的是在图像在绘制到当前屏幕前,需要先进行一次渲染,之后才绘制到当前屏幕。在第一次渲染时,GPU(Core Animation)或CPU(Core Graphics)需要额外的一块内存来进行渲染,完成后再绘制到屏幕。offscreen到onscreen需要进行上下文切换,这个切换的性能消耗是昂贵的。
因此,我们必须避免不必要的离屏渲染。
造成离屏渲染的原因有:
CALayer
的cornerRadiu
,edgeAntialiasingMask
,allowsEdgeAntialiasing
属性CALayer
的maskToBounds
设为YES
CALayer
的shadow
属性CALayer
的mask
属性CALayer
的allowsGroupOpacity
属性设为YES
而且opacity
小于1等等...
由此可见,很多常用属性都会造成离屏渲染,在性能要求高的地方,就需要使用另外的实现方案。比如使用shadowPath
代替使用shadow+shadowOffset+shadowColor
;在需要使用圆形图片的tableview
里,使用cornerRadius
设置圆角是下下之选,可以用一张中间为透明圆形的图片进行遮盖来达到圆形的效果,或者在使用前就把图片裁剪为圆形。
3、Blending(混合绘制)
GPU会放弃绘制那些完全被其他图层遮盖的内容。如果两个图层叠加在一起,上面的图层不是完全不透明的,那么GPU便会计算合并两个图层的透明重叠像素,这个过程便是blending
,这同样也是一个消耗资源的过程。
因此,不要随便把一个视图或图层的backgroundColor
设为透明。
用Xcode
打开你的项目,选择工具栏上的Product->Profile
,编译成功后会打开Instrument
,在Choose a profile template
页面下选择Core Animation
,进入主界面。(如果需要检测动画帧数,需要使用真机)
点击左上方红色的录制按钮,开始检测:
在页面右下方,有一系列的复选框,利用这几个选项,我们可以很轻松的检查上面所提到的问题:(下面解释摘抄自iOS核心动画高级技巧第十二章)
shouldRasterizep
属性的时候,耗时的图层绘制会被缓存,然后当做一个简单的扁平图片呈现。当缓存再生的时候这个选项就用红色对栅格化图层进行了高亮。如果缓存频繁再生的话,就意味着栅格化可能会有负面的性能影响了。Core Animation
被强制生成一些图片,然后发送到渲染服务器,而不是简单的指向原始指针。这个选项把这些图片渲染成蓝色。复制图片对内存和CPU使用来说都是一项非常昂贵的操作,所以应该尽可能的避免。Core Animation Instruments
以每毫秒10次的频率更新图层调试颜色。对某些效果来说,这显然太慢了。这个选项就可以用来设置每帧都更新(可能会影响到渲染性能,而且会导致帧率测量不准,所以不要一直都设置它)。shadowPath
或者shouldRasterize
来优化。GLKView
或者CAEAGLLayer
,那如果不显示蓝色块的话就意味着你正在强制CPU渲染额外的纹理,而不是绘制到屏幕。Core Graphics
绘制的图层)。这种绘图的速度很慢。如果频繁发生这种情况的话,这意味着有一个隐藏的bug或者说通过增加缓存或者使用替代方案会有提升性能的空间。需要注意的重点是这3个:
勾选后,检查你的应用界面,blended layer
会显示为红色,不透明的为绿色,红色越少越好,如果你的界面一片红海,那就是时候好好优化了。
勾选后,如果在你使用了shouldRasterize
的地方界面显示为绿色,则表示使用正确性能良好,如果为红色,则需要考虑优化了。(第一次加载时会显示红色,因为这时还没缓存成功,需要检测重用的过程中(比如tableview
上下滚动)的变化)
如上所述,离屏渲染的地方都标记为黄色。并非所有的黄色区域都是需要优化的,比如UINavigationBar
,因为需要做背景模糊效果,因此它需要离屏渲染。
上述的很多原因分析,希望大家不要有强迫症的感觉,要求自己的所有项目必须按这个标准执行,因为这是不可能的,只是给大家提供一个优化方向,以及出了性能问题以后的分析依据。但是在日常的编码过程中,也要时刻把性能的意识放在心上,写出优秀的代码。