【问题标题】:Draw line via Coregraphic: crash at renderInContext通过Coregraphic画线:在renderInContext崩溃
【发布时间】:2019-02-28 13:47:13
【问题描述】:

我正在使用 CoreGraphics 画一条线。我刚刚更新了 Xcode 10 和 iOS 12。在 iOS 12 中,我的应用程序崩溃了。虽然,它在 iOS 11.4.1 及之前的版本中仍然运行良好。我无法解决问题。请在下面找到我的代码

-(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];
} 

下面是touchesMoved方法。

-(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];
}

问题是[self.layer renderInContext:context];(void)drawRect:(CGRect)rect 函数的代码崩溃。 drawRect 函数调用时间过长(约 5000 次)和内存过载(约 20Gb)导致应用程序崩溃。 iOS 12 和 Xcode 10 会不会有变化?

我修复了这个问题。 更新我的新 toucheMoved() 函数:

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

【问题讨论】:

  • 与我的问题相同。你修好了吗?
  • @trungduc 似乎它们不是同一个问题,它在 iOS12 之前的我的应用程序中运行良好。仅在 iOS12 中崩溃。这很奇怪。 renderInContext 会一直调用 drawRect 直到内存过载,然后在 iOS12 中崩溃。
  • 嗨!我刚刚遇到了同样的问题。你修好了吗?
  • @Matthieu:我修好了。在 touchMoved() 函数中。我打电话给[self setNeedsDisplay] 而不是renderInContext。我只在 drawRect() 函数中使用renderInContext

标签: objective-c iphone core-graphics xcode10 ios12


【解决方案1】:

我的解决方法是

不要让layer renderInContext在drawRect中递归调用

(我的代码很快)

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
    }
...
}

【讨论】:

  • 这是个好主意,我认为这是一个很好的解决方案。简单明了。顺便说一句,我认为我们应该找到发生这种情况的原因,以及何时会在drawRect 中调用renderInContext
猜你喜欢
  • 2023-04-07
  • 2018-07-04
  • 1970-01-01
  • 1970-01-01
  • 2012-06-30
  • 2021-08-03
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多