代码之家  ›  专栏  ›  技术社区  ›  Vladimir

CatiledLayer绘图崩溃

  •  1
  • Vladimir  · 技术社区  · 15 年前

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

    UIView
    ----UIScrollView
    --------TiledView (UIView subclass, uses CATiledLayer for drawing)
    ----OverlayView (UIView subclass)
    

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

    tiledView.transform = CGAffineTransformMakeRotation(angle);
    

    平铺视图的绘制方法:

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

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

    套印格式视图的绘制方法:

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

    最初一切正常,但在一些视图播放(例如来回滚动等)之后,它在一个绘图函数中的某个随机行上崩溃。例如,应用程序在网上崩溃:

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

    堆栈:

    #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:]
    

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

    1 回复  |  直到 15 年前
        1
  •  7
  •   Vladimir    15 年前

    找到了问题的解决方案。如苹果公司所述 technical note CATiledLayer 使用单独的线程获取其磁贴的内容:

    CatiledLayer实现其 使用背景线绘制 要获取每个图块的内容, 但提供的绘图功能 由uikit依赖于全球环境 叠加,当一个catiledLayer 开始渲染,使用任何uikit的 绘图功能可能导致竞争 条件。

    所以解决方案是将所有绘图代码从 -drawRect: 方法到 -drawLayer:inContext: 并绘制使用 只有 核心图形功能。用核心图形绘制也需要坐标系之间的一些转换-这 post 来自苹果论坛的帮助(参见 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]);
    }
    
    推荐文章