我正在尝试保存和恢复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);
}
答案 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)
..根据你的代码!, 您似乎在保存之前恢复上下文。 第一件事:
Pop
Store(push)
的一般规则必须有Restore(pop)
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