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 秒的延迟,其中没有其他任何事情发生。请参阅下面的日志作为示例。注意不规则的行为:在第一秒,一些图块被重绘多次,而另一些则只重绘一次。然后停顿 5 秒,循环重新开始。

这是在带有 IOS6.0 的模拟器上测试的(我选择那个版本,因为早期版本有另一个在 6.0 中修复的错误:它们有时会绘制两次相同的图块)。

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: call(只是一个不重复答案的链接)。

很快:您应该调用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 回答