【问题标题】:CATiledLayer drawing crashCATiledLayer 绘图崩溃
【发布时间】:2010-02-19 09:23:28
【问题描述】:

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

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

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

tiledView.transform = CGAffineTransformMakeRotation(angle);

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

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

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

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

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

【问题讨论】:

    标签: iphone uiview crash drawing catiledlayer


    【解决方案1】:

    找到问题的解决方案。正如 Apple 的 technical note 中所述,CATiledLayer 使用单独的线程来获取其磁贴的内容:

    CATiledLayer 实现了它的 使用后台线程绘图 获取每个图块的内容, 但是提供的绘图功能 通过 UIKit 依赖于全局上下文 堆栈,因此当 CATiledLayer 开始渲染,使用任何 UIKit 的 绘图函数可能会导致比赛 条件。

    因此解决方案是将所有绘图代码从-drawRect: 方法移动到-drawLayer:inContext: 并使用 Core Graphics 函数进行绘图。使用 CoreGraphics 绘图还需要在坐标系之间进行一些转换 - 苹果论坛的 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]);
    }
    

    【讨论】:

    • 您能否详细说明如何将 TiledView 本身挂接到滚动视图上?谢谢
    • 只需将其添加为子视图并将滚动视图的 contentsSize 设置为适当的值
    • 显然,从 iOS 4.0 开始,这不再需要 - 根据已接受答案中链接的技术说明。在 drawRect 中绘图:现在允许,无需通过坐标转换跳过箍。
    猜你喜欢
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多