问题描述
我在我的应用程序中使用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).
我已经记录了一个,因为我认为这是不正确的。但我很难知道如何解决这个问题。你有好的想法吗?
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}}
推荐答案
我已经发布了类似问题的答案:(只是一个链接在这里不重复答案)。
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:的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!