CATiledLayer绘图崩溃

Vla*_*mir 1 iphone crash drawing uiview catiledlayer

在我的应用程序中,我使用了以下视图层次结构:

UIView
----UIScrollView
--------TiledView (UIView subclass, uses CATiledLayer for drawing)
----OverlayView (UIView subclass)
Run Code Online (Sandbox Code Playgroud)

简而言之 - TiledView显示大平铺图像我也将自定义旋转应用于该视图:

tiledView.transform = CGAffineTransformMakeRotation(angle);
Run Code Online (Sandbox Code Playgroud)

TiledView的绘图方法:

- (void)drawRect:(CGRect)rect {
    // Drawing code
    CGContextRef context = UIGraphicsGetCurrentContext();  
    ...
  NSString *fileName = [NSString stringWithFormat:@"tile_%d_%d.jpg", y + 1, x + 1];
    UIImage *image = [UIImage imageNamed:fileName];
    [image drawInRect:rect];
 }
Run Code Online (Sandbox Code Playgroud)

UIScrollView允许滚动和缩放其内容.
叠加视图覆盖UIScrollView,具有透明背景并执行一些自定义绘图.我使用单独的视图来确保线条宽度和字体大小不受滚动视图中缩放比例的影响.

OverlayView的绘图方法:

- (void)drawRect:(CGRect)rect {
    // Drawing code
    [super drawRect:rect];

    // Custom drawing code
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetRGBStrokeColor(context, 1.0, 1.0, 0, 1);
   CGContextSetLineWidth(context, lineWidth);

    CGContextBeginPath(context);
    CGContextMoveToPoint(context, (int)startPoint.x,(int) startPoint.y);

    if (usesMidPoint)
        CGContextAddLineToPoint(context, (int)midPoint.x, (int)midPoint.y); 
    CGContextAddLineToPoint(context, endPoint.x, endPoint.y);

    CGContextStrokePath(context);
}
Run Code Online (Sandbox Code Playgroud)

最初一切正常,但是在玩了一些视图(例如,来回滚动等)之后,它会在其中一个绘图函数中的某个随机行上崩溃.作为一个示例应用程序在线崩溃:

CGContextSetRGBStrokeColor(context, 1.0, 1.0, 0, 1); 
Run Code Online (Sandbox Code Playgroud)

堆栈:

#0  0x00503088 in CGColorEqualToColor
#1  0x00505430 in CGGStateSetStrokeColor
#2  0x005053b6 in setStrokeColorWithComponents
#3  0x0056150f in CGContextSetRGBStrokeColor
#4  0x000764ab in -[GADrawView drawRect:] at GADrawView.m:38
#5  0x016a7a78 in -[UIView(CALayerDelegate) drawLayer:inContext:]
#6  0x0077c007 in -[CALayer drawInContext:]
Run Code Online (Sandbox Code Playgroud)

我错过了几个图形上下文之间所需的任何同步吗?或者可能有更好的方法来做我正在尝试的事情?

Vla*_*mir 8

找到问题的解决方案.如Apple的技术说明中 所述,CATiledLayer使用单独的线程来获取其tile的内容:

CATiledLayer通过使用后台线程来获取每个图块的内容来实现其绘图,但是UIKit提供的绘图函数依赖于全局上下文堆栈,因此当CATiledLayer开始渲染时,使用任何UIKit的绘图函数都会导致一场竞争.

所以解决方案是将所有绘图代码从-drawRect:方法移动到-drawLayer:inContext:使用Core Graphics函数绘制.与CoreGraphics在绘图还需要坐标系统之间的一些转换-这一职位由苹果论坛帮助他们(见方法实现).drawLayer:

所以正确的绘图代码TiledView:

- (void)drawRect:(CGRect)rect {
    //Still need to have this method implemented even if its empty!
}

-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx
{
    // Do all your drawing here. Do not use UIGraphics to do any drawing, use Core Graphics instead.
    // convert the CA coordinate system to the iPhone coordinate system
    CGContextTranslateCTM(ctx, 0.0f, 0.0f);
    CGContextScaleCTM(ctx, 1.0f, -1.0f);

    CGRect box = CGContextGetClipBoundingBox(ctx);

    // invert the Y-coord to translate between CA coords and iPhone coords
    CGPoint pixelTopLeft = CGPointApplyAffineTransform(box.origin, CGAffineTransformMakeScale(1.0f, -1.0f));

    NSString *tileUrlString = [self urlForPoint:pixelTopLeft];

    UIImage *image = [UIImage imageNamed:tileUrlString];
    CGContextDrawImage(ctx, box, [image CGImage]);
}
Run Code Online (Sandbox Code Playgroud)