11

我正在尝试保存和恢复 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);
}
4

3 回答 3

20

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

CGContextSaveGState() 的文档中

每个图形上下文都维护着一堆图形状态。请注意,并非当前绘图环境的所有方面都是图形状态的元素。例如,当前路径不被视为图形状态的一部分,因此在调用 CGContextSaveGState()函数时不会保存。

图形状态堆栈应在drawRect:您的 . 既然你没有推上一个,就没有弹出来。所有这一切意味着您不能将绘图作为图形状态存储在堆栈上,然后再将其恢复。

如果您所担心的只是缓存您的绘图,那是由CALayer支持您的UIView(在 iPhone 上)为您完成的。如果你所做的只是移动你的视图,它不会被重绘。只有当您手动告诉它这样做时,它才会被绘制。如果您确实必须更新绘图的一部分,我建议将静态元素拆分到它们自己的视图中,或者CALayers只重绘更改的部分。

于 2009-09-18T22:24:37.013 回答
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);

也许您正在尝试做其他事情。

于 2009-09-18T19:46:04.730 回答
0

..根据您的代码!,您似乎正在恢复上下文,然后再保存它。第一件事:

  1. 创建上下文
  2. 保存它的状态,也就是 push
  3. 根据上下文做一些事情
  4. 恢复上下文又名Pop
  5. Store(push)每个必须有一般规则Restore(pop)
  6. 完成后释放上下文!,这是指他们拥有的那些CGCreate上下文CGCopy,,,

示例代码:

        [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 
于 2013-10-27T22:05:12.410 回答