0

В моем приложении у меня есть модуль рисования изображений CoreGraphics. Приложение случайно разбивается на CGContextAddPath() вызов функции. Путь - это CGPathRef объект, созданный с использованием CGPathCreateMutable() вызов функции. Пример код приведен ниже:iOS 8.3 - EXC_BAD_ACCESS в образе рисования CoreGraphics

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 
    if (touching) return; 

    //start a new path 
    path = CGPathCreateMutable(); 
    //set the path's starting point 
    UITouch *touch = (UITouch *)[touches anyObject]; 
    CGPathMoveToPoint(path, NULL, [touch locationInView:m_view].x, [touch locationInView:m_view].y); 

    touching = YES; 
} 

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 
    if (touching){ 
     //get the current location of the touch event 
     UITouch *theTouch = (UITouch *)[touches anyObject]; 
     pathPoint = [theTouch locationInView:m_view]; 
     CGPathAddLineToPoint(path, NULL, pathPoint.x, pathPoint.y);  
     [canvasLayer setNeedsDisplay]; 
    } 
} 

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
    if (!touching) return; 

    //create a new image context 
    UIGraphicsBeginImageContext(CGSizeMake(backgroundLayer.bounds.size.width, backgroundLayer.bounds.size.height)); 

    //grab a reference to the new image context 
    CGContextRef ctx = UIGraphicsGetCurrentContext(); 
    //push the image context to the top of the drawing stack 
    UIGraphicsPushContext(ctx); 
    //set the blend mode to prevent white pixels from 
    //covering up the lines that have already been drawn 
    CGContextSetBlendMode(ctx, kCGBlendModeDarken); 

    if (cacheImage != nil) { 
     //draw the cached state of the image to the image context and release it 
     [cacheImage drawInRect:CGRectMake(0, 0, backgroundLayer.bounds.size.width, backgroundLayer.bounds.size.height)]; 
    } 

    //blend the drawing layer into the image context 
    [canvasLayer drawInContext:ctx]; 
    //we're done drawing to the image context 
    UIGraphicsPopContext(); 
    //store the image context so we can add to it again later 
    cacheImage = UIGraphicsGetImageFromCurrentImageContext(); 

    //we're finished with the image context altogether 
    UIGraphicsEndImageContext(); 
    touching = NO; 
    //release the path 
    CGPathRelease(path); 

    //update the background layer (we'll need to draw the cached image to the background) 
    [backgroundLayer setNeedsDisplay]; 
} 

- (void)drawLayer:(CATiledLayer *)layer inContext:(CGContextRef)ctx { 
    //this method is handling multiple layers, so first 
    //determine which layer we're drawing to 
    if (layer == canvasLayer) { 
     if (!touching) return; 

     //add the path to the context 
     CGContextAddPath(ctx, path); /***Exception points to this line***/ 
     //set a line width and draw the path 
     CGContextSetLineWidth(ctx, 6.0f);//---thikness of line 
     CGContextStrokePath(ctx); 
    } 
    else if (layer == backgroundLayer) { 
     //remember the current state of the context 
     CGContextSaveGState(ctx); 
     //the cached image coordinate system is upside down, so do a backflip 
     CGContextTranslateCTM(ctx, 0, backgroundLayer.bounds.size.height); 
     CGContextScaleCTM(ctx, 1.0, -1.0); 
     //draw the image 
     CGImageRef ref = cacheImage.CGImage; 
     CGContextDrawImage(ctx, backgroundLayer.bounds, ref); 
     //restore the context to its pre-flipped state 
     CGContextRestoreGState(ctx); 
    } 
} 

отчет о сбое диагностики, полученный из устройства показывает:

Exception Type: EXC_BAD_ACCESS (SIGBUS) 
Exception Subtype: KERN_PROTECTION_FAILURE at 0x090d3330 
Triggered by Thread: 13 

    Thread 13 name: Dispatch queue: com.apple.root.default-qos 
Thread 13 Crashed: 
0 ???         0x090d3330 0 + 151860016 
1 CoreGraphics       0x22886b6c 0x22874000 + 76652 
2 CoreGraphics       0x228a036e 0x22874000 + 181102 
3 MyApplication      0x001c8062 0xb6000 + 1122402 
4 QuartzCore       0x256d08fc 0x25695000 + 243964 
5 QuartzCore       0x257a9e86 0x25695000 + 1134214 
6 QuartzCore       0x256fdd14 0x25695000 + 429332 
7 libdispatch.dylib     0x30f99866 0x30f8b000 + 59494 
8 libdispatch.dylib     0x30f9a89e 0x30f8b000 + 63646 
9 libsystem_pthread.dylib    0x3110eda6 0x3110e000 + 3494 
10 libsystem_pthread.dylib    0x3110eaf8 0x3110e000 + 2808 

Когда я symbolicate адреса памяти в докладе аварии, точки исключения из CGContextAddPath (СТХ, дорожка);. Это вызвано явным выпуском пути с использованием CGPathRelease (path);? Если я прокомментирую функцию release, приложение не сработает, но приведет ли она к утечке памяти?

ответ

1

Вы уничтожаете путь в касании, но drawLayer может быть вызван после этого.

+0

Мы создаем объект path в touchhesBegan() и отпустите его в функции touchesEnded() после окончания контекста изображения. В каком случае может быть вызвана функция drawLayer() после уничтожения объекта пути? – Queen

+0

Я не уверен, что вы делаете, но обычно окна, представления и слои могут обновляться, даже если вы их не трогаете или не принудительно обновляете с помощью setNeedsDisplay. – Tapani