Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is drawing rounded corner in drawRect: faster than using CALayer setCornerRadius?

In 2011's WWDC video session 121, to improve performance of the UI, the presenter chose to draw the rounded corners using UIBezierPath in drawRect:, rather than setting corner radius directly on a layer.

Why is drawing using UIBezierPath necessarily faster? drawRect: happens in software which can be slow too.

like image 569
Evil Nodoer Avatar asked Jul 11 '13 19:07

Evil Nodoer


People also ask

How does corner radius work?

Definition of CORNER RADIUS:A larger corner radius produces a more rounded corner, while a small corner radius produces a sharper corner that is closer in shape to the point of a square cut corner label (where the corner is the sharp point that is the natural result of two lines meeting at a 90° angle).

How would you round the corners of one of your views?

You can give it round corners by changing the cornerRadius property of the view's layer . and smaller values give less rounded corners. Both clipsToBounds and masksToBounds are equivalent. It is just that the first is used with UIView and the second is used with CALayer .

What is corner radius in IOS?

Discussion. Setting the radius to a value greater than 0. 0 causes the layer to begin drawing rounded corners on its background. By default, the corner radius does not apply to the image in the layer's contents property; it applies only to the background color and border of the layer.


1 Answers

Short answer: probably just stick with CALayer’s cornerRadius until you see a performance problem.

Long answer:

We first need to distinguish between “drawing” and “compositing”.

Drawing on iOS is the simple act of filling a texture with pixels (a CPU limited task). Compositing is the act of flattening all of those textures into a single frame to print to the screen (a GPU limited task). Generally speaking, when scrolling or animating you’re mostly taxing the GPU, which is good cause things like shifting all pixels down by one is something the GPU eats for breakfast.

-drawRect: is pure drawing, and uses the CPU to fill a texture. CALayer’s cornerRadius is done at the compositing step, and stresses the GPU.

Using -drawRect: has a very high initial cost (it could easily take longer than one frame) and non-trivial memory usage, but scrolls very smoothly after that (it’s just a texture now like any other texture). Using CALayer’s corner radius is ridiculously fast to create a bunch of views with corner radius, but once you get more than a dozen of them you can say goodbye to scrolling speed (because the GPU not only has to do normal scrolling duties but also needs to keep adding corner radius back onto your view).

But don’t take my word for it, have some math. I adapted Florian Kugler’s benchmark and ran on a iPhone 4S running iOS 6.1.3. I measure how many views can be initially created in 1/60th of a second, then measure how many views can be animated before the frame rate drops below 60fps. In other words: upfront cost vs framerate cost.

                                        | -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

(note that the app is killed for using too much memory at 500 -drawRect: views)

At the end of the day, in my own projects I tend to stick to CALayer’s cornerRadius as much as possible. I’ve rarely needed more than a couple of views with round corners and -drawRect: just has too much of an initial performance hit. And subclassing a view just to round the corners is just, ugh.

But no matter what method you end up choosing, make sure you measure and pay attention to how smooth and responsive your app is, and respond accordingly.

like image 90
shusta Avatar answered Nov 03 '22 01:11

shusta