在drawRect中绘制圆角:比使用CALayer setCornerRadius更快?

时间:2013-07-11 19:14:09

标签: ios cocoa-touch

在2011年的WWDC视频会议121中,为了提高用户界面的性能,演示者选择使用drawRect:中的UIBezierPath绘制圆角,而不是直接在图层上设置角半径。

为什么使用UIBezierPath绘图必然更快? drawRect:在软件中发生,也可能很慢。

1 个答案:

答案 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:只是有太多的初始性能影响。并且将视图子类化为圆角只是,呃。

但无论您最终选择何种方法,请务必衡量并注意应用的平滑性和响应性,并做出相应的响应。