2011-10-18 12 views
1

CATiledLayerに問題があります。 iOS 4では問題なく動作していますが、iOS 5では問題があります。drawRectは、同時に2つの異なるスレッドから同じ矩形に対して2回呼び出されています。この呼び出しで画像を読み込むので、ビューの読み込みが非常に遅くなります。ios5:同じRectのCATiledLayerでdrawRectが2回呼び出されました

2011-10-18 14:07:18.802 APP[12436:19003] drawRect:{{0, 400}, {368, 400}} (view:<TiledScrollColumn: 0x91bc880; frame = (0 1600; 368 5400); userInteractionEnabled = NO; layer = <CATiledLayer: 0x919c1b0>>) 
2011-10-18 14:07:18.805 APP[12436:1b103] drawRect:{{0, 400}, {368, 400}} (view:<TiledScrollColumn: 0x91bc880; frame = (0 1600; 368 5400); userInteractionEnabled = NO; layer = <CATiledLayer: 0x919c1b0>>) 

何が起こる可能性があるのか​​、それを修正するために何ができるのでしょうか?私はビューで特別なことをしていない、それはphotoscrollerの例に基づいています。

バスティアン

答えて

1

回避策が見つかりました。シリアル(一度に1つの操作のみ)ディスパッチキューを作成し、内部にすべての図面を実行してから結果をキャッシュします。

私が使用しているコードを添付しました。デリゲートやその他の手法で描画するのではなく、CATiledLayerのサブクラスを使用しています。

また、不確定なタイルキャッシュを作成しています。状況によってはメモリの問題が発生する可能性があります。キャッシュ内のタイル数を管理し、古いものを削除する必要があるかもしれません。メモリ不足の警告が受信されると、キャッシュもクリアする必要があります。誰かがこれらの改善点を追加したら、私の答えを編集してそれを含めてください。

- (id)init 
{ 
    if (!(self = [super init])) 
    return nil; 

    tileCache = [[NSMutableDictionary alloc] init]; 

    return self; 
} 

- (void)drawInContext:(CGContextRef)layerContext 
{ 
    // CATiledLayer has a bug, where it spawns multiple threads for drawing, and then tries to draw the same tile multiple times simultaniously on separate threads 
    // so we create our own serial background queue, and do dispatch_async on it. This will cache each draw operation, so multiple calls on one tile are efficient 
    static dispatch_queue_t drawQueue = NULL; 
    static dispatch_once_t onceToken; 
    dispatch_once(&onceToken, ^{ 
     drawQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); 
    }); 

    dispatch_sync(drawQueue, ^{ 

    // no map ways? draw nothing 
    if (!self.mapWays) 
     return; 

    // load from cache? 
    CGRect tileRect = CGContextGetClipBoundingBox(layerContext); 
    NSString *tileCacheKey = [NSString stringWithFormat:@"%f%f%f%f", tileRect.origin.x, tileRect.origin.y, tileRect.size.width, tileRect.size.height]; 
    __block UIImage *tileImage; 
    dispatch_sync(dispatch_get_main_queue(), ^{ 
     tileImage = [tileCache objectForKey:tileCacheKey]; 
    }); 
    if (tileImage) { 
     CGContextDrawImage(layerContext, tileRect, tileImage.CGImage); 
     return; 
    } 

    // prepare to draw the tile image 
    UIGraphicsBeginImageContextWithOptions(tileRect.size, YES, 0); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    // filp coords 
    CGContextTranslateCTM(context, 0, tileRect.size.height); 
    CGContextScaleCTM(context, 1.0, -1.0); 


    /*** do actual drawing here ***/ 


    // store tile in cache 
    tileImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    dispatch_sync(dispatch_get_main_queue(), ^{ 
     [tileCache setObject:tileImage forKey:tileCacheKey]; 
    }); 

    // draw the tile 
    CGContextDrawImage(layerContext, tileRect, tileImage.CGImage); 
    }); 
} 
+1

NSMutableDictionaryの代わりにNSCacheを使用して、メモリの問題を処理すると思います。また、この方法では、CATiledLayerの利点を無効にするように見えます。なぜなら、これを行うことによって画像全体をメモリにロードするからです。 – Joel

関連する問題