Saving and restoring CGContext

与世无争的帅哥 提交于 2019-11-29 18:34:20

问题


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);
}

回答1:


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.




回答2:


Don't you want to Save first and then Restore? If you are restoring before a save, then there is no context to restore, and you'd get an underflow.

Here is the way I have used it:

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextClipToRect(context, CGRectMake(stripe[i][8], stripe[i][9], stripe[i][10], stripe[i][11]));
CGContextDrawLinearGradient(context, gradient, CGPointMake(15, 5), CGPointMake(15, 25), 0);
CGContextRestoreGState(context);

or:

  CGContextRef context = UIGraphicsGetCurrentContext();
  CGContextSaveGState(context);
  CGContextAddRect(context, originalRect);
  CGContextClip(context);

  [self drawInRect:rect];

  CGContextRestoreGState(context);

Maybe you are trying to do something else.




回答3:


.. Based on your code !, It seems that you are Restoring the Context before Saving it. First Thing First:

  1. Create a context
  2. Save its state, aka push
  3. Do some stuff with the context
  4. Restore the context aka Pop
  5. General rule for each Store(push) there must be Restore(pop)
  6. Release the context when you are done with it !, This refers to those context/s which they have CGCreate, CGCopy,

Sample code:

        [super drawRect:rect];
        CGContextRef ctx = UIGraphicsGetCurrentContext();
// save context 
        CGContextSaveGState(ctx);
// do some stuff 
        CGContextSetRGBStrokeColor(ctx, 1.0, 0.5, 0.5, 1.0);
        // drawing vertical lines
        CGContextSetLineWidth(ctx, 1.0);
        for (int i = 0; i < [columns count]; i++) {
            CGFloat f = [((NSNumber*) [columns objectAtIndex:i]) floatValue];
            CGContextMoveToPoint(ctx, f+(i*20.5), 0.5);
            CGContextAddLineToPoint(ctx, f+(i*20.5), self.bounds.size.height);
        }
// restore context 
        CGContextRestoreGState(ctx);
// do some other stuff 
        // drawing hozizontal lines
        CGContextSetLineWidth(ctx, 1.0);
         CGContextSetRGBStrokeColor(ctx, 0.12385, 0.43253, 0.51345, 1.0);
        for (int i = 0; i < [columns count]; i++) {
            CGFloat f = [((NSNumber*) [columns objectAtIndex:i]) floatValue];
            CGContextMoveToPoint(ctx, 0.5, f+(i*20.5));
            CGContextAddLineToPoint(ctx,self.bounds.size.width,f+(i*20.5));
        }

        CGContextStrokePath(ctx);
    }
// No context CGContextRelease , since we never used CGContextCreate 


来源:https://stackoverflow.com/questions/1446446/saving-and-restoring-cgcontext

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!