对基于 app 的动画,Core Animation 是提高帧速率很好的方式,但并不是使用它一定能提高性能。尤其在 OS X ,你仍必须做出选择关于使用 Core Animation 行为最高效的方法。所有性能相关的问题,你应该使用 Instruments 随时间的推移去测量、追踪你 app 中的性能,这样你就能确定性能确实提高了,而不是更慢了。
给你的 OS X 视图选择最好的重绘策略
NSView
类默认的重绘策略是保存类的原始绘制行为,即使视图是图层支持视图。如果你在 app 中使用图层支持视图,你应该检查重回策略,选择能为你 app 提供最好性能的方式。在多数情况下,默认的策略并不是能提供最好性能的。而 NSViewLayerContentsRedrawOnSetNeedsDisplay 策略更可能减少你 app 的绘制数量、提升性能。其它策略可能对具体类型的视图会提供更好的性能。
关于视图重绘策略的更多信息,请参见OS X 视图的图层重绘策略会影响性能。
更新 OS X 的图层去优化你的渲染路径
在 OS X v10.8 及以后版本,视图有两个选项来更新底部图层的内容。你在OS X v10.7及以前版本更新图层支持视图时,图层将视图 drawRect:
方法中的绘图命令捕获到背景位图图像中。缓存绘制命令是高效的,当它不是在所有情况下都是最高效的。如果你知道如何直接提供图层的内容,而不用真正地渲染它们,你可以使用 updateLayer
方法去实现。
关于渲染的不同路径的更多信息,包含涉及 updateLayer
方法,请参见使用委托提供图层内容。
提示和技巧概述
这有几种方法使你的图层实现更加高效。然而,与之前的优化一样,在尝试优化之前,你始终应该测量代码的当前性能。 这为你提供了基准线,你可以使用它来确定优化是否有效。
尽量使用不透明的图层
将图层的 opaque
属性设置为 YES
,让 Core Animation 知道它不需要操作图层的 alpha 通道。没有 alpha 通道意味着合成器不需要将图层内容和背景内容混合,这会在渲染期间节省时间。然而,该属性主要与作为图层支持视图的一部分的图层,或 Core Animation 创建底层位图的情况相关。如果你直接给图层的 contents
属性赋值图像,图像的 alpha 通道都会被保留,不管 opaque
属性的值是什么。
对 CAShapeLayer 对象使用简单路径
CAShapeLayer 类通过将你提供的路径在合成时渲染成位图图像,来创建它的内容。这样做的优点就是图层总是以最好的分辨率绘制路径,但是这个优点也造成了额外的渲染时间。如果你提供的路径是复杂的,光栅化路径可能会非常耗时间。如果图层的尺寸经常变化(肯定会经常重绘),花费在绘制上的时间会累积起来,成为性能瓶颈。
减少图形图层绘制时间的方法就是将复杂图形分割成简单图形。合成器使用简单路径去绘制多个 CAShapeLayer 对象并拼接在一起,比绘制一个复杂路径要快得多。这是因为绘制操作发生在 CPU 上,而合成发生在 GPU 上。然而,与这种性质的任何简化一样,潜在的性能提升取决于你的内容。因此,在优化之前测量代码性能是非常重要的,这样你就有比较的基准线了。
为相同图层显式设置图层内容
如果你在多个图层对象上使用同一图像,需自己加载图像并直接将它赋值给图层对象的 contents 属性。给 contents 属性赋值图像可防止图层为后备存储分配内存。相反,图层会使用你提供的图像作为它的后备存储。当几个图层使用同一图像时,这意味着所有图层共享同一内容,而不是它们自己再拷贝图像。
始终设置图层尺寸为整型数值
为了得到最好结果,你始终应该将你图层对象的宽高设置为整型。虽然你使用单精度数字给图层对象的宽高指定值,但图层边界最终用于创建位图图像。为宽高指定整数值简化了 Core Animation 创建和管理后备存储和其他图层信息必须做的工作。
需要时,使用异步图层渲染
你在你 delegate 的 drawLayer:inContext:
方法,或者你视图的 drawRect:
方法所做的任何绘制,通常都是在你的 app 主线程同步执行的。然而,在某些情况下,同步绘制你的内容可能不会提供最好的性能。如果你发现你的动画执行效率并不是特别好,你应该试着使图层的 drawsAsynchronously
属性生效,去将操作移到后台线程。如果你这样做了,请确保你的代码是线程安全的。并且,你始终应该在将异步绘制代码放到你的项目之前,测量你项目代码性能。
给图层添加阴影时指定阴影路径
让 Core Animation 决定阴影的形状是非常耗时的,这会影响你 app 的性能。你应该使用CALayer 的 shadowPath 属性显式地指定阴影形状,而不是让 Core Animation 决定阴影的形状。你给该属性指定路径对象时,Core Animation 使用该形状绘制、缓存阴影效果。对于图层的阴影形状尽量不要改变,这通过减少 Core Animation 的渲染量极大地提高了性能。