Сохранение и восстановление CGContext - PullRequest
9 голосов
/ 18 сентября 2009

Я пытаюсь сохранить и восстановить 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 ]

18 голосов
/ 19 сентября 2009

Я думаю, вы, возможно, неправильно истолковываете, что делают CGContextSaveGState() и CGContextRestoreGState(). Они помещают текущее графическое состояние в стек и извлекают его, позволяя вам преобразовать текущее пространство рисования, изменить стили линий и т. Д., А затем восстановить состояние до того, каким оно было до установки этих значений. Он не хранит элементы чертежа, такие как контуры.

Из документации по CGContextSaveGState () :

Каждый графический контекст поддерживает стек графических состояний. Обратите внимание, что не все аспекты текущего рисунка окружающая среда являются элементами графическое состояние. Например, текущий путь не считается частью графическое состояние и, следовательно, не сохраняется при вызове CGContextSaveGState() функция.

Стек графического состояния должен быть сброшен в начале вашего drawRect:, поэтому вы получаете ошибки, когда пытаетесь вытолкнуть графическое состояние из стека. Так как ты не нажал одну, не было ничего, чтобы выскочить. Все это означает, что вы не можете сохранить чертеж в виде графического состояния в стеке, а затем восстановить его.

Если все, что вас беспокоит, это кэширование вашего рисунка, то это делается для вас CALayer, который поддерживает ваш UIView (на iPhone). Если все, что вы делаете, это перемещает ваш взгляд, он не будет перерисован. Он будет нарисован, только если вы вручную скажете это сделать. Если вам необходимо обновить часть чертежа, я рекомендую разбить статические элементы на их собственные виды или CALayers, чтобы перерисовывалась только изменяемая часть.

7 голосов
/ 18 сентября 2009

Разве вы не хотите сначала сохранить, а затем восстановить? Если вы восстанавливаете данные перед сохранением, тогда нет контекста для восстановления, и вы получите недостаточное значение.

Вот как я это использовал:

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 голосов
/ 28 октября 2013

.. На основании вашего кода!, Кажется, вы восстанавливаете контекст перед его сохранением. Первая вещь первая:

  1. Создать контекст
  2. Сохранить свое состояние, он же push
  3. Делать что-то с контекстом
  4. Восстановление контекста aka 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 
...