B2G HCM Trn Minh T
B2G HCM Trn Minh T

Reputation: 66

Draw line via Coregraphic: crash at renderInContext

I'm using CoreGraphics to draw a line. I have just updated Xcode 10 and iOS 12. In iOS 12, my Application is crashed. Although, it still works well in iOS 11.4.1 and version before. I am not able to solve the issue. please find my code below

-(void)drawRect:(CGRect)rect
{
    CGPoint mid1 = midPoint(previousPoint1, previousPoint2); 
    CGPoint mid2 = midPoint(currentPoint, previousPoint1);

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    [self.layer renderInContext:context];

    CGContextMoveToPoint(context, mid1.x, mid1.y);
    CGContextAddQuadCurveToPoint(context, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y); 
    CGContextSetLineCap(context, kCGLineCapRound);
    CGContextSetLineWidth(context, self.lineWidth);
    CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);

    CGContextSetShadow(context, CGSizeMake(-16.00, -5.0f), 5.0f);

    CGContextStrokePath(context);

    [super drawRect:rect];
    [curImage release];
} 

Below is the touchesMoved method.

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{

    UITouch *touch  = [touches anyObject];

    previousPoint2  = previousPoint1;
    previousPoint1  = [touch previousLocationInView:self];
    currentPoint    = [touch locationInView:self];

    // calculate mid point
    CGPoint mid1    = midPoint(previousPoint1, previousPoint2); 
    CGPoint mid2    = midPoint(currentPoint, previousPoint1);

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, mid1.x, mid1.y);
    CGPathAddQuadCurveToPoint(path, NULL, previousPoint1.x, previousPoint1.y, mid2.x, mid2.y);
    CGRect bounds = CGPathGetBoundingBox(path);
    CGPathRelease(path);

    CGRect drawBox = bounds;

    //Pad our values so the bounding box respects our line width
    drawBox.origin.x        -= self.lineWidth * 2;
    drawBox.origin.y        -= self.lineWidth * 2;
    drawBox.size.width      += self.lineWidth * 4;
    drawBox.size.height     += self.lineWidth * 4;

    UIGraphicsBeginImageContext(drawBox.size);
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
    curImage = UIGraphicsGetImageFromCurrentImageContext();
    [curImage retain];
    UIGraphicsEndImageContext();
   [self setNeedsDisplayInRect:drawBox];

}

CGPoint midPoint(CGPoint p1, CGPoint p2)
{
    return CGPointMake((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5);
}


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{

    UITouch *touch = [touches anyObject];

    previousPoint1 = [touch previousLocationInView:self];
    previousPoint2 = [touch previousLocationInView:self];
    currentPoint = [touch locationInView:self];

    [self touchesMoved:touches withEvent:event];
}

The issue is code crash at [self.layer renderInContext:context]; of (void)drawRect:(CGRect)rect function. drawRect function is called too much time (About 5000 times) and Overload of Memory (About 20Gb) cause crashing app. Could there be changes in iOS 12 and Xcode 10?

I Fixed this issue. Update my new toucheMoved() function:

- (void) touchesMoved: (NSSet*) touches withEvent: (UIEvent*) event
{    
previousPoint2 = previousPoint;
previousPoint = [touch previousLocationInView:self];
location = [touch locationInView:self];

CGPoint mid1 = midPoint(previousPoint, previousPoint2);
CGPoint mid2 = midPoint(location, previousPoint);

CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, mid1.x, mid1.y);
CGPathAddQuadCurveToPoint(path, NULL, previousPoint.x, previousPoint.y, mid2.x, mid2.y);
CGRect bounds = CGPathGetBoundingBox(path);
CGPathRelease(path);

CGRect drawBox = bounds;

drawBox.origin.x -= self.lineWidth * 2;
drawBox.origin.y -= self.lineWidth * 2;
drawBox.size.width += self.lineWidth * 4;
drawBox.size.height += self.lineWidth * 4;

UIGraphicsBeginImageContextWithOptions(totalDrawBox.size, self.opaque, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGAffineTransform affineMoveLeftTop = CGAffineTransformMakeTranslation(-(int)totalDrawBox.origin.x, -(int)totalDrawBox.origin.y);
CGContextConcatCTM(context, affineMoveLeftTop);
float iOSVersion = [[UIDevice currentDevice].systemVersion floatValue];
if (iOSVersion >= 12) {
    [self setNeedsDisplay];
} else {
    [self.layer renderInContext: context];
}
curImage = UIGraphicsGetImageFromCurrentImageContext();
CGContextStrokePath(context);
UIGraphicsEndImageContext();
}

Upvotes: 5

Views: 588

Answers (1)

saranpol
saranpol

Reputation: 2197

My work around is

Don't let layer renderInContext recursive call in drawRect

(My code is swift)

var mIsInDrawLoop = false

// -(void)drawRect:(CGRect)rect
override func draw(_ rect: CGRect) {
...
    if(!mIsInDrawLoop) {
        mIsInDrawLoop = true
        layer.render(in: context)
        // [self.layer renderInContext:context];
        mIsInDrawLoop = false
    }
...
}

Upvotes: 3

Related Questions