How to clear and then redraw a quartz drawing - iphone

I'm making a complex drawing using quartz based on passed in information. The only part I haven't been able to figure out is how do I clear the lines, rectangles, etc that I've already drawn? Basically, I want to erase the whole drawing and just draw it again from the new data.

If you set your UIView's clearContextBeforeDrawing property to YES, then the system should take care of filling its area with its backgroundColor before calling its drawRect: method.

If you want to clear something that's not tracked as part of the current state, it's probably less expensive to just release your old context and start a new one.

Related

Continuous drawing with Quartz? frame by frame possible?

I've been working on custom drawings using drawRect in UIView subclasses. That's cool, but you have to wait until the end of the run loop for drawRect to be called and I'm wondering how you can control frame by frame animations where you change the drawings over time, or if this is possible? Perhaps Quartz isn't really designed for this type of animated graphics? I gather that perhaps it is designed for static drawings that don't change so frequently.
Quartz by itself its not able to sustain a high frame rate, due to its need to redraw everything each time. But you can have Quartz work together with CoreAnimation to have Quartz based animations. The idea behind this is that you can cache previously drawn content inside CALayer objects and then use CoreAnimation to create the continuous drawing effect.
A good example of this technique can be see in the AccelerometerGraph sample code provided by Apple. Inside this sample the UIView subclass that uses this technique is the "GraphView" object. Basically this object draws as completely new only a portion of the graph (the newly generated segments), backs it in a dedicated layer and then animates the layers in order to provide the "scrolling graph" animation.
Clearly this technique works only when you have full control of the drawing elements and can manage this incremental way of adding objects in the screen. Of course things become much more complicated when you must redraw many different parts of the screen and you need to modify previously generated layers.
Anyway have a look at the mentioned code: it is quite interesting.
Your app should exit to the run loop before each frame. Do all your custom frame animation setup between each frame. So frame-by-frame drawing in drawRect should work just fine. This can work in iOS apps at a 60 Hz frame update rate, not just for static views, as long as all your methods between frame times, as well as your drawRects, are fast enough. Chop them up if needed.

Any possible way for CoreGraphics to not lag when drawrect is being called from touches moved?

I am calling setNeedsDisplay from touches moved (and have also tried not calling from touches moved, but instead from a 0.05 timer) and the drawrect method is always laggy. Is their anyway to change this? I am doing a lot of drawing in drawrect but I have no idea for a solution to fix the lag. Even when the timer was called at a 1.0 interval than it still lagged when the timer called the selector. Also, I have no leaks (I checked using Xcode analyze feature ). Please help!!
EDIT: I am calling setNeedsDisplay, not drawRect from my timer/method
EDIT: It seems that wherever core graphics does somethings with a lot of drawing it always lags. I am positive I have no memory leaks and I even created another painting app and it lags (what is the fix to this?? Please help mee)
Slightly edited transcript of comments on one of the other answers:
I am drawing a color a hue based color picker (in draw rect a line for each hue value is drawn)
… Are you drawing 360 rectangles?
Yes, I am ….
I draw the images of 360 rectangles of different colors into the image of one UIImageView. than I release the rectangles. (I use a for loop for the rectangle allocation/releasing)
So, you are doing this 360 times:
Create an image.
Draw a rectangle into this image. (Or not, if step 1 loads the image from a file.)
Draw that image into another image.
Release the image.
And then you pass the image that you drew all the smaller images into to a UIImageView for the actual display?
It sounds like you're trying to cache this in the image, which should help after the first time if you do it right, but this doesn't need to be slow in the first place.
You already have a custom view. Drop the image view, and cut out all this rectangle-drawing (or image-drawing) code. If you have image files with the individual colored rectangles, delete them.
In your view's drawRect:, create a gradient and draw that. Your drawRect: will be three lines long and should be much, much, much faster.
I am calling drawrect from touches moved
don't do that.
(and have also tried not calling from touches moved, but instead from a 0.05 timer)
don't do that.
and the drawrect method is always laggy. Is their anyway to change this? I am doing a lot of drawing in drawrect but I have no idea for a solution to fix the lag. Even when the timer was called at a 1.0 interval than it still lagged when the timer called the selector. Also, I have no leaks (I checked using Xcode analyze feature ). Please help!!
Yes!
You should NEVER call drawRect explicitly. Use setNeedsDisplay instead and the drawing will be performed when the system is ready for it.
EDIT:
Based on the fact that you were already doing this. Your problem is then your drawRect is just too slow. What are you trying to draw?
If you can figure out which parts of the screen needs change, you can call setNeedsDisplayInRect to speed it up by just redrawing the changed rect instead of the whole screen.
You can also run a background thread to prepare frames in a buffer and use that to draw on screen. It depends on the kind of drawing you are doing. Here is a blog post I found on this topic.
Or you can use OpenGL ES to draw.

Continuously drawing into an iPhone bitmap object? What am I missing?

I am pretty sure this is a straightforward problem I must be confused about (I am a total newbie on the iPhone): I am trying to continuously draw shapes using the CG APIs into a bitmap object, and to always show an up-to-date version of that bitmap on the screen, inside a UIScrollView object so the user can pan, zoom, etc.
Using UIView with drawRect is no good because this is an ongoing thing -- I have a separate thread where all the drawing commands are issued, and I need them to be applied and accumulated on that same framebuffer (kind of like a web page rendering engine). What I keep seeing is that all GCContext APIs related to images seem to CREATE a brand new image whenever you want it rendered to the screen. That sounds bad because it forces the creation of another copy of the image.
I guess I am looking for a way to create an off-screen bitmap, render to it as much as I want using Core Graphics, and whenever I want to, blt that image to the screen, but still retaining the ability to keep drawing to it and blt it to the screen again, later on.
Thanks in advance!
You could use a CGLayer. Create it once with CGLayerCreateWithContext() and later retrieve the layer's context with CGLayerGetContext() whenever you need to draw into it.
To draw the layer into another graphics context, call CGContextDrawLayerAtPoint() or CGContextDrawLayerInRect().

Improving drawing performance on custom UIView

I have a custom UIView which is composed of many images, their positions are changing in response to the user touch.
The view must track the user touch and i'm experiencing a performance bottleneck in the drawing of such view, preventing me to follow the input in realtime.
At the beginning i was drawing everything in the [UIView drawRect:] method and of course it was way too slow because everything was redrawn even if not necessary.
Then, i used more CALayers to update only the layer that was changing and this gave me much better responsiveness.
But still, when i have to draw the same image many times on a layer it takes up to 500ms.
Since the images are placed at fixed positions it there a way to pre-draw them? Should i consider putting them in many CALayers and just hide/show them?
Also, i don't understand why a [CALayer setNeedsDisplayInRect:] exists but the delegate has (apparently) no way to know what the invalid rect is to optimize the drawing.
Solution
Following the advice in the answer I finally created many CALayers for the images and set the contents property the first time the layer was being shown. This is a lazy-loading compromise: in a first attempt i set the contents of every layer at the creation time but this caused to pre-draw any possible image on the program launch, freezing the application for seconds.
From the documentation for -[CALayer drawInContext:]:
Default implementation does nothing. The context may be clipped to protect valid layer content. Subclasses that wish to find the actual region to draw can call CGContextGetClipBoundingBox. Called by the display method when the contents property is being updated.
The default implementation of display calls drawInContext: on an automatically-created context; presumably setting the bounding box as well (which is presumably passed to drawRect:).
If you're drawing several static images, I'd just stick each one in its own UIView; I don't think the overhead is that big (if it is, the CALayer overhead should be smaller). If they all animate, I'd definitely use UIView/CALayer. If some of them don't animate (much) and you notice significant slowness, you can pre-render those. It's a trade-off between rendering in drawRect: (or similar) and layer compositing on the GPU, but in general I'd assume that the latter is much faster.

Drawing/Rendering a UIView Within a Separate Thread so NSTimer Always Fires Timely

I'm using a NSTimer to fire a drawRect within the app's main view. The drawRect draws a few images, and blends each using kCGBlendModeScreen (which is an absolute must). However, the drawRect takes just a tad longer than desired, so the timer doesn't always get fired at the desired rate (more like half as often).
I've optimized the graphics used as much as I feel is possible, so I'm wondering if it's possible to "outsource" the drawing by creating a new view, and calling that view's drawRect from within a thread created inside of the timer's callback method. (In other words, thread the call to a new view's drawRect, such as [someNewView setNeedsDisplay] ...)
If so, how might I approach something like that, in code?
...
I'd use Core Animation, but I remember reading that it didn't support alpha blend modes. If I'm wrong, I'd be open to seeing some example code that allows animation of all the images in separate transformations (e.g. individual rotations for each image), while still keeping them able to blend using kCGBlendModeScreen that I'm currently implementing.
Thanks for any tips!
The answer is "no." You should never, ever do drawing(or anything with UIKit) from a secondary thread. If you're experiencing performance issues, you should perform all of your computations on another thread ahead of drawing so that drawing takes a minimal amount of time.