1

私のアプリケーションでは、次のビュー階層を使用しています。

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

最初はすべて問題なく動作しますが、ビューを操作した後(たとえば、前後にスクロールするなど)、描画関数の1つでランダムな線でクラッシュします。例として、アプリがオンラインでクラッシュします。

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

複数のグラフィックスコンテキスト間で必要な同期が欠落していますか?または、私が試していることを行うためのより良い方法があるかもしれませんか?

4

1 に答える 1

8

問題の解決策が見つかりました。Apple のテクニカル ノート CATiledLayerで説明されているように、別のスレッドを使用してタイルのコンテンツをフェッチします。

CATiledLayer は、バックグラウンド スレッドを使用して各タイルのコンテンツを取得することによって描画を実装しますが、UIKit によって提供される描画関数はグローバル コンテキスト スタックに依存するため、CATiledLayer がレンダリングを開始するときに、UIKit の描画関数のいずれかを使用すると、競合状態。

したがって、解決策は、すべての描画コードを-drawRect:メソッドからに移動し、 Core Graphics 関数のみ-drawLayer:inContext:を使用して描画することです。CoreGraphics を使用した描画には、座標系間の変換も必要です - Appleフォーラムからのこの投稿はそれらに役立ちました (メソッドの実装を参照)。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]);
}
于 2010-02-22T08:44:23.487 に答える