5

アプリで CATiledLayer を使用しているため、そのレイヤーの描画はバックグラウンド スレッドで行われます。つまり、デリゲートの drawLayer:inContext: メソッドはバックグラウンド スレッドから呼び出されます。CATiledLayer の一部を無効にするために使用される setNeedsDisplayInRect は、常にメイン スレッドから呼び出されます。

これらは独立したスレッドであるため、バックグラウンド スレッドが drawLayer:inContext メソッドにある間に setNeedsDisplayInRect が呼び出されることがあります。その状況では setNeedsDisplayInRect が無視されることに気付きました (drawLayer:inContext は再度呼び出されません)。

それは正しくないと思うので、Apple にバグを記録しました。しかし、私はこの状況を回避する方法を理解するのに苦労しています。良いアイデアはありますか?

編集:

次のコードを使用して、Stanislaw の回答をテストしました。

- (void) setNeedsDisplayInRect:(CGRect)rect
{
    NSLog(@"setNeedsDisplayInRect:%@", NSStringFromCGRect(rect));
    [super setNeedsDisplayInRect:rect];
}

- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)gc
{
    CGRect bounds = CGContextGetClipBoundingBox(gc);
    NSLog(@"drawLayer:inContext: bounds=%@", NSStringFromCGRect(bounds));

    dispatch_async(dispatch_get_current_queue(), ^{
        [self setNeedsDisplayInRect:bounds];
    });

    CGContextSetFillColorWithColor(gc, testColor.CGColor);
    CGContextFillRect(gc, bounds);
    sleep(0.2); // simulate the time it takes to draw complicated graphics
    NSLog(@"end drawLayer:inContext: bounds=%@", NSStringFromCGRect(bounds));
}

与えられたように、コードによって描画が無期限に繰り返されますが、setNeedsDisplayInRect: と対応する drawLayer:inContext: の間に最大 5 秒の遅延が発生し、他に何も起こっていない場合があります。例として以下のログを参照してください。不規則な動作に注意してください。最初の 1 秒間に、複数回再描画されるタイルもあれば、1 回だけ再描画されるタイルもあります。その後、5 秒間の一時停止があり、サイクルが最初からやり直されます。

これは、IOS6.0 のシミュレーターでテストされました (以前のバージョンには 6.0 で修正された別のバグがあるため、このバージョンを選択しました。同じタイルが 2 回描画されることがあります)。

2012-10-27 15:51:38.771 TiledLayerTest[39934:15a13] drawLayer:inContext: bounds={{0, 300}, {300, 180}}
2012-10-27 15:51:38.774 TiledLayerTest[39934:15a13] end drawLayer:inContext: bounds={{0, 300}, {300, 180}}
2012-10-27 15:51:38.774 TiledLayerTest[39934:1570f] drawLayer:inContext: bounds={{300, 0}, {20, 300}}
2012-10-27 15:51:38.776 TiledLayerTest[39934:1570f] end drawLayer:inContext: bounds={{300, 0}, {20, 300}}
2012-10-27 15:51:38.776 TiledLayerTest[39934:1630b] setNeedsDisplayInRect:{{0, 300}, {300, 180}}
2012-10-27 15:51:38.777 TiledLayerTest[39934:1540f] setNeedsDisplayInRect:{{300, 0}, {20, 300}}
2012-10-27 15:51:38.780 TiledLayerTest[39934:15a13] drawLayer:inContext: bounds={{300, 0}, {20, 300}}
2012-10-27 15:51:38.781 TiledLayerTest[39934:15a13] end drawLayer:inContext: bounds={{300, 0}, {20, 300}}
2012-10-27 15:51:38.782 TiledLayerTest[39934:1540f] setNeedsDisplayInRect:{{300, 0}, {20, 300}}
2012-10-27 15:51:38.789 TiledLayerTest[39934:1570f] drawLayer:inContext: bounds={{0, 0}, {300, 300}}
2012-10-27 15:51:38.791 TiledLayerTest[39934:15a13] drawLayer:inContext: bounds={{300, 300}, {20, 180}}
2012-10-27 15:51:38.792 TiledLayerTest[39934:15a13] end drawLayer:inContext: bounds={{300, 300}, {20, 180}}
2012-10-27 15:51:38.793 TiledLayerTest[39934:1570f] end drawLayer:inContext: bounds={{0, 0}, {300, 300}}
2012-10-27 15:51:38.795 TiledLayerTest[39934:1540f] setNeedsDisplayInRect:{{0, 0}, {300, 300}}
2012-10-27 15:51:38.795 TiledLayerTest[39934:1540f] setNeedsDisplayInRect:{{300, 300}, {20, 180}}
2012-10-27 15:51:38.798 TiledLayerTest[39934:15a13] drawLayer:inContext: bounds={{0, 0}, {300, 300}}
2012-10-27 15:51:38.800 TiledLayerTest[39934:15a13] end drawLayer:inContext: bounds={{0, 0}, {300, 300}}
2012-10-27 15:51:38.802 TiledLayerTest[39934:1630b] setNeedsDisplayInRect:{{0, 0}, {300, 300}}
2012-10-27 15:51:38.806 TiledLayerTest[39934:1570f] drawLayer:inContext: bounds={{0, 300}, {300, 180}}
2012-10-27 15:51:38.808 TiledLayerTest[39934:1630b] setNeedsDisplayInRect:{{0, 300}, {300, 180}}
2012-10-27 15:51:38.809 TiledLayerTest[39934:1570f] end drawLayer:inContext: bounds={{0, 300}, {300, 180}}
2012-10-27 15:51:38.813 TiledLayerTest[39934:15a13] drawLayer:inContext: bounds={{0, 300}, {300, 180}}
2012-10-27 15:51:38.816 TiledLayerTest[39934:1630b] setNeedsDisplayInRect:{{0, 300}, {300, 180}}
2012-10-27 15:51:38.816 TiledLayerTest[39934:15a13] end drawLayer:inContext: bounds={{0, 300}, {300, 180}}
2012-10-27 15:51:43.774 TiledLayerTest[39934:1540f] drawLayer:inContext: bounds={{0, 300}, {300, 180}}
2012-10-27 15:51:43.776 TiledLayerTest[39934:1540f] end drawLayer:inContext: bounds={{0, 300}, {300, 180}}
2012-10-27 15:51:43.776 TiledLayerTest[39934:1630f] drawLayer:inContext: bounds={{0, 0}, {300, 300}}
4

2 に答える 2

0

同様の問題に対する回答を投稿しました: setNeedsDisplayInMapRect は新しい drawMapRect: 呼び出しをトリガーしません(ここで回答を複製しないためのリンクのみ)。

手短に言えば、 setNeedsDisplayInRectメソッドの呼び出しをdispatch_get_main_queue() にディスパッチする必要があります。

于 2012-10-26T23:02:45.747 に答える
-1

NSRecursiveLock次の方法でa を試すことができます。

- (void) setNeedsDisplayInRect:(CGRect)rect
{
    [self.lock lock]
    NSLog(@"setNeedsDisplayInRect:%@", NSStringFromCGRect(rect));
    [super setNeedsDisplayInRect:rect];
    [self.lock unlock]
}

- (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)gc
{
    [self.lock lock]
    CGRect bounds = CGContextGetClipBoundingBox(gc);
    NSLog(@"drawLayer:inContext: bounds=%@", NSStringFromCGRect(bounds));


    // drawing code


    NSLog(@"end drawLayer:inContext: bounds=%@", NSStringFromCGRect(bounds));
    [self.lock unlock]
}

これによりsetNeedsDisplayInRect、描画の進行中に が呼び出されないようになります。ただし、これはパフォーマンスに影響を与える可能性があります。これはlock、メイン スレッドがブロックされる可能性があり、複数のタイルを並行して描画できないためです。

于 2012-10-27T15:11:13.207 に答える