【问题标题】:iOS 8.3 - EXC_BAD_ACCESS in CoreGraphics Image DrawingiOS 8.3 - CoreGraphics 图像绘图中的 EXC_BAD_ACCESS
【发布时间】:2015-04-27 12:06:36
【问题描述】:

在我的应用程序中,我有一个 CoreGraphics 图像绘制模块。应用程序在 CGContextAddPath() 函数调用时随机崩溃。路径是使用 CGPathCreateMutable() 函数调用创建的 CGPathRef 对象。示例代码如下:

-(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

当我在崩溃报告中符号化内存地址时,异常指向CGContextAddPath(ctx, path);。它是由使用 CGPathRelease(path); 显式释放路径引起的吗?如果我注释掉释放函数,应用程序不会崩溃,但是会不会引入内存泄漏?

【问题讨论】:

    标签: ios memory-management core-graphics cgcontext symbolicatecrash


    【解决方案1】:

    您在 touchEnded 中破坏了路径,但之后可能会调用 drawLayer。

    【讨论】:

    • 我们在 touchesBegan() 中创建路径对象,并在结束图像上下文后在 touchesEnded() 函数中释放它。什么情况下我们销毁路径对象后可以调用drawLayer()函数?
    • 我不确定您在做什么,但通常窗口、视图和图层可能会更新,即使您不触摸它们或使用 setNeedsDisplay 强制更新。
    猜你喜欢
    • 1970-01-01
    • 2020-05-31
    • 1970-01-01
    • 2015-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-03
    • 1970-01-01
    相关资源
    最近更新 更多