保存和恢复CGContext

时间:2009-09-18 19:30:28

标签: iphone core-graphics quartz-graphics cgcontext

我正在尝试保存和恢复CGContext以避免第二次进行繁重的绘图计算而我收到错误<Error>: CGGStackRestore: gstack underflow

我做错了什么?这样做的正确方法是什么?

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

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

    initialized = YES;

    //heavy drawing computation and drawing

    CGContextSaveGState(context);
}

3 个答案:

答案 0 :(得分:18)

我认为你可能误解了CGContextSaveGState()CGContextRestoreGState()所做的事情。它们将当前图形状态推送到堆栈并将其弹出,让您转换当前绘图空间,更改线条样式等,然后将状态恢复为设置这些值之前的状态。它不存储绘图元素,如路径。

来自documentation on CGContextSaveGState()

  

每个图形上下文维护一个   堆栈的图形状态。注意   并非当前绘图的所有方面   环境是元素的   图形状态。例如,   当前路径不被视为其中的一部分   图形状态,因此   你拨打电话时没有保存   CGContextSaveGState()功能。

应该在drawRect:开始时重置图形状态堆栈,这就是当您尝试从堆栈中弹出图形状态时出现错误的原因。既然你没有按过一个,就没有一个可以弹出。所有这些意味着您无法将图形作为图形状态存储在堆栈中,然后在以后恢复。

如果你担心的只是缓存你的绘图,那就是CALayer支持你的UIView(在iPhone上)。如果你正在做的只是移动你的视图,它将不会被重绘。只有手动告诉它才能绘制它。如果您必须更新部分图形,我建议将静态元素拆分为自己的视图或CALayers,以便只重绘更改的部分。

答案 1 :(得分:7)

您不想先保存然后还原吗?如果您在保存之前进行恢复,则没有要恢复的上下文,并且您将获得下溢。

以下是我使用它的方式:

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

或:

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

  [self drawInRect:rect];

  CGContextRestoreGState(context);

也许你正在尝试做别的事情。

答案 2 :(得分:0)

..根据你的代码!, 您似乎在保存之前恢复上下文。 第一件事:

  1. 创建上下文
  2. 保存状态,即推送
  3. 用上下文做一些事情
  4. 恢复上下文Pop
  5. 每个Store(push)的一般规则必须有Restore(pop)
  6. 完成上下文后释放上下文!,这是指他们拥有CGCreateCGCopy
  7. 的上下文

    示例代码:

            [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