回避策が見つかりました。シリアル(一度に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);
});
}
NSMutableDictionaryの代わりにNSCacheを使用して、メモリの問題を処理すると思います。また、この方法では、CATiledLayerの利点を無効にするように見えます。なぜなら、これを行うことによって画像全体をメモリにロードするからです。 – Joel