在2011年的WWDC视频会议121中,为了提高用户界面的性能,演示者选择使用drawRect:中的UIBezierPath绘制圆角,而不是直接在图层上设置角半径。
为什么使用UIBezierPath绘图必然更快? drawRect:在软件中发生,也可能很慢。
答案 0 :(得分:23)
简短的回答:可能只是坚持使用CALayer的cornerRadius,直到你发现性能问题为止。
答案很长:
我们首先需要区分“绘图”和“合成”。
在iOS上绘图是用像素填充纹理的简单行为(CPU限制任务)。合成是将所有这些纹理展平为单个帧以打印到屏幕的行为(GPU限制任务)。一般来说,当滚动或动画时,你主要是对GPU征税,这是好事,因为将所有像素向下移动的东西是GPU吃早餐的东西。
-drawRect:是纯绘图,并使用CPU填充纹理。 CALayer的cornerRadius在合成步骤完成,并强调GPU。
使用-drawRect:具有非常高的初始成本(它可能容易花费超过一帧)和非平凡的内存使用,但在此之后滚动非常平滑(它现在只是一个纹理,就像任何其他纹理一样)。使用CALayer的角半径非常快,可以创建一堆具有角半径的视图,但是一旦你得到十几个就可以告别滚动速度(因为GPU不仅要做正常的滚动任务,还需要继续将角半径添加回您的视图。)
但是不要相信我的话,有一些数学。我改编了Florian Kugler’s benchmark并在运行iOS 6.1.3的iPhone 4S上运行。我测量在1/60秒内最初可以创建多少视图,然后测量在帧速率降至60fps以下之前可以设置多少视图。换句话说:前期成本与帧率成本。
| -drawRect: | CALayer’s cornerRadus max number of views rendered in 16.6ms | 5 views | 110 views max number of views animating at 60fps | ~400 views | 12 views
(请注意,因为在500 -drawRect:views中使用了太多内存而导致应用被杀死)
在一天结束时,在我自己的项目中,我倾向于尽可能地坚持CALayer的cornerRadius。我很少需要带圆角的几个视图和-drawRect:只是有太多的初始性能影响。并且将视图子类化为圆角只是,呃。
但无论您最终选择何种方法,请务必衡量并注意应用的平滑性和响应性,并做出相应的响应。