setNeedsDisplayInRect在drawLayer期间调用:inContext: [英] setNeedsDisplayInRect called during drawLayer:inContext:

查看:650
本文介绍了setNeedsDisplayInRect在drawLayer期间调用:inContext:的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的应用程序中使用CATiledLayer,因此,该图层的绘制是在后台线程中完成的。也就是说,我的委托的drawLayer:inContext:方法是从后台线程调用的。用于无效部分CATiledLayer的setNeedsDisplayInRect总是从主线程调用。

I use a CATiledLayer in my app, and as a result, drawing of that layer is done in a background thread. That is, the drawLayer:inContext: method of my delegate is called from a background thread. The setNeedsDisplayInRect used to invalidate parts of the CATiledLayer is always called from the main thread.

因为它们是独立线程,所以偶尔会发生setNeedsDisplayInRect被调用,而后台线程在drawLayer:inContext方法中。我注意到setNeedsDisplayInRect在这种情况下被忽略(drawLayer:inContext不会再次调用)。

Because they are independent threads, it occasionally happens that the setNeedsDisplayInRect is called while the background thread is in the drawLayer:inContext method. I have noticed that the setNeedsDisplayInRect is ignored in that situation (drawLayer:inContext is not called again).

我已经记录了一个 bug给苹果,因为我认为这是不正确的。但我很难知道如何解决这个问题。你有好的想法吗?

I have logged a bug to Apple, because I think that is not correct. But I have a hard time figuring out how to work around this situation. Do you have good ideas?

编辑:

我使用以下代码测试了Stanislaw的答案:

I tested Stanislaw's answer using the following code:

- (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秒,其中没有发生其他事情。请参见下面的日志作为示例。注意不规则的行为:在第一秒,一些瓷砖重绘多次,其他只有一次。

As given, the code does cause drawing to repeat indefinitely, but sometimes there is a delay up to 5 seconds between the setNeedsDisplayInRect:, and the corresponding drawLayer:inContext:, in which nothing else is happening. See the log below as example. Note the irregular behaviour: in the first second, some tiles are redrawn multiple times, others only once. Then there is a pause of 5 seconds, and the cycle starts over again.

这是在模拟器上用IOS6.0测试的(我选择那个版本,因为早期版本有另一个bug修复在6.0:他们绘制相同的瓷砖两次有时)。

This was tested on the simulator with IOS6.0 (I choose that version, because earlier versions have another bug that is fixed in 6.0: they draw the same tiles twice sometimes).

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


推荐答案

我已经发布了类似问题的答案: setNeedsDisplayInMapRect不会触发新的drawMapRect:调用(只是一个链接在这里不重复答案)。

I've posted my answer to the similar issue: setNeedsDisplayInMapRect doesn't trigger new drawMapRect: call (just a link to not duplicate the answer here).

setNeedsDisplayInRect 方法到dispatch_get_main_queue()。

Shortly: you should dispatch a call of setNeedsDisplayInRect method to dispatch_get_main_queue().

这篇关于setNeedsDisplayInRect在drawLayer期间调用:inContext:的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆