Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Incrementally adding to a UIView

In my iOS app, I've created a view that renders a path drawn with a finger using UIBezierPath in real time while drawing. Unfortunately, I'm having performance problems as the path gets long (several hundred vertices) and it becomes impractical to draw the entire path every time the view is refreshed.

I tried splitting the path into many different segments which allows me to draw only the segments that are in the rectangle passed to me in drawRect: and that helps significantly, but drawing is still slow; many segments are redrawn unnecessarily when sections are added to the path in a region of the screen which already contains parts of the path.

I don't remove anything from the view, so I tried to enable clearsContextBeforeDrawing and only draw the latest segment each time drawRect: is called, but it seems there is a large amount of anecdotal evidence online suggesting that this property doesn't do anything and I also could not seem to make it work at all.

What is the best way to speed up drawing?

From what I've read, it looks like my best option is drawing to an (offscreen) bitmap context so I can add little by little and copying it to the graphics context being displayed on the screen, but I also read that this is often slow both in allocating the context and because of the RGBA to RGB conversion that is required in rendering the image to the screen.

It looks like I may be able to do something involving a CALayer (either with or without the offscreen buffer) – it's unclear to me how drawing on a layer works and whether it would circumvent any of the problems I've seen. The contents property accepts a CGImageRef; can I make a CGImage then update it incrementally without redrawing everything? Also, is it possible to add to the contents of a CALayer without redrawing the whole thing?

Any insights would be greatly appreciated.


Edit: For the bounty, please provide an example of how to properly initialize the image buffer, draw a cubic bezier path onto it, and copy it to the screen appropriately. Also please make a note of why to use your method – I don't know if using CGBitmapContextCreate is the best way or if there's something else I should be using.

like image 332
Sophie Alpert Avatar asked Jun 13 '11 02:06

Sophie Alpert


1 Answers

BezierPaths are good because they are vectors, no matter resolution of your view they will look nice. However if you don't need to resize your view then there is no need of calculating everything everytime. Just do the calculate the last arc/line and draw it onto the previous (offscreen) buffer, that should improve performance.

I remember doing that kind of stuff and performance was not such a big problem I got around 12fps in an iPhone 3GS. Which is not that bad. (I was not using bezier path exactly I was doing some image processing using CGImageRefs and raw rgba buffers which should be the most expensive part of this approach. Calculating only one arc/line of a BezierPath is very cheap)

like image 150
nacho4d Avatar answered Sep 27 '22 21:09

nacho4d