2009-09-18 123 views
8

我試圖保存並恢復CGContext,以避免第二次執行重繪圖計算,並且出現錯誤<Error>: CGGStackRestore: gstack underflow保存和恢復CGContext

我在做什麼錯?什麼是正確的方法來做到這一點?

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

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

    initialized = YES; 

    //heavy drawing computation and drawing 

    CGContextSaveGState(context); 
} 

回答

5

難道你不想先保存然後恢復?如果您在保存前恢復,則沒有上下文可以恢復,並且會發生下溢。

這裏是我已經用它的方式:

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

也許你正在嘗試做別的事情。

+0

對不起,我已經編輯我的代碼,並再次得到同樣的錯誤 – cocoatoucher 2009-09-18 19:52:00

17

我想你可能會誤解CGContextSaveGState()CGContextRestoreGState()做什麼。他們將當前圖形狀態推送到堆棧並將其彈出,讓您轉換當前繪圖空間,更改線條樣式等,然後將狀態恢復到設置這些值之前的狀態。它不存儲繪圖元素,如路徑。

documentation on CGContextSaveGState()

每個圖形上下文保持 堆棧的圖形狀態。請注意, 並非所有方面的當前圖紙 環境都是 圖形狀態的元素。例如, 當前路徑不被視爲 圖形狀態的一部分,因此在調用 CGContextSaveGState()函數時不會保存 。

圖形狀態堆棧應在您的drawRect:開始時重置,這就是爲什麼當您嘗試從堆棧彈出圖形狀態時出現錯誤。既然你沒有推一個,就沒有東西可以彈出。所有這一切意味着您不能將繪圖作爲圖形狀態存儲在堆棧上,然後再恢復。

如果所有你擔心的是緩存你的繪圖,那麼CALayer支持你的UIView(在iPhone上)。如果你所做的只是移動視圖,它不會被重畫。只有在您手動指示的情況下才會繪製。如果您必須更新繪圖的一部分,我建議將靜態元素分解到各自的視圖或CALayers中,以便只更改所繪製的部分。

0

..根據你的代碼!, 在保存之前,似乎你正在恢復上下文。 第一件事首先:

  1. 創建上下文
  2. 保存其狀態,又名推
  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