Saving and restoring CGContext

cocoatoucher picture cocoatoucher · Sep 18, 2009 · Viewed 19k times · Source

I'm trying to save and restore a CGContext to avoid doing heavy drawing computations for a second time and I'm getting the error <Error>: CGGStackRestore: gstack underflow.

What am I doing wrong? What is the correct way to do this?

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();

    if (initialized) {
        CGContextRestoreGState(context);
        //scale context
        return;
    }

    initialized = YES;

    //heavy drawing computation and drawing

    CGContextSaveGState(context);
}

Answer

Brad Larson picture Brad Larson · Sep 19, 2009

I think you might be misinterpreting what CGContextSaveGState() and CGContextRestoreGState() do. They push the current graphics state onto a stack and pop it off, letting you transform the current drawing space, change line styles, etc., then restore the state to what it was before you set those values. It does not store drawing elements, like paths.

From the documentation on CGContextSaveGState():

Each graphics context maintains a stack of graphics states. Note that not all aspects of the current drawing environment are elements of the graphics state. For example, the current path is not considered part of the graphics state and is therefore not saved when you call the CGContextSaveGState() function.

The graphics state stack should be reset at the start of your drawRect:, which is why you're getting errors when you try to pop a graphics state off the stack. Since you hadn't pushed one on, there was none to pop off. All of this means that you can't store your drawing as graphics state on the stack, then restore it later.

If all you are worried about is caching your drawing, that is done for you by the CALayer that backs your UIView (on the iPhone). If all you are doing is moving your view around, it won't be redrawn. It will only be drawn if you manually tell it to do so. If you do have to update part of the drawing, I recommend splitting the static elements off into their own views or CALayers so that only the part that changes is redrawn.