问题描述
布拉德·拉森(Brad Larson)为CADisplayLink
冻结问题提供了解决方案滚动视图正在滚动.
Brad Larson delivered a solution for the CADisplayLink
freeze issue when scroll views are scrolling.
我的OpenGL ES绘制方法由CADisplayLink
调用,我尝试了Brad的技术,但无法使其起作用.核心问题是我的OpenGL ES视图由UIScrollView
托管,并且当U IScrollView
滚动时,CADisplayLink
会停止触发.
My OpenGL ES draw method is called by a CADisplayLink
, and I tried Brad's technique but can't make it work. The core problem is that my OpenGL ES view is hosted by a UIScrollView
, and when the UIScrollView
scrolls, the CADisplayLink
stops firing.
Brad所描述的技术应该使CADisplayLink
甚至在滚动过程中也继续触发(通过将其添加到NSRunLoopCommonModes
而不是默认的runloop模式),并使用一种花哨的信号灯技巧,渲染回调应确保当UIKit太占用时,它不会呈现.
The technique Brad described is supposed to let the CADisplayLink
continue to fire even during scrolling (by adding it to NSRunLoopCommonModes
instead of the default runloop mode), and using a fancy semaphore trick the rendering callback is supposed to ensure that it doesn't render when UIKit is too occupied.
问题在于,无论如何,信号量技巧都会阻止绘制渲染回调.
The problem is though that the semaphore trick prevents the rendering callback from drawing, no matter what.
首先,我在OpenGL ES视图的initWithFrame
方法中创建串行GCD队列和信号灯,如下所示(在主线程上):
First, I create the serial GCD queue and semaphore in the initWithFrame
method of my OpenGL ES view like this (on the main thread):
frameRenderingQueue = dispatch_queue_create("com.mycompany.crw", DISPATCH_QUEUE_SERIAL);
frameRenderingSemaphore = dispatch_semaphore_create(1);
显示链接已创建并添加到NSRunLoopCommonModes
:
The display link is created and added to NSRunLoopCommonModes
:
CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(renderFrame)];
[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
渲染回调执行Brad的技术:
The render callback performs Brad's technique:
- (void)renderFrame {
if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) != 0) {
NSLog(@"return"); // Gets called ALWAYS!
return;
}
dispatch_async(drawingQueue, ^{
@autoreleasepool {
// OpenGL ES drawing code
dispatch_semaphore_signal(frameRenderingSemaphore);
}
});
}
dispatch_semaphore_wait
函数始终返回YES
,因此render回调从不渲染.即使我不滚动.
The dispatch_semaphore_wait
function always returns YES
and thus the render callback never renders. Even when I'm not scrolling.
我想我在这里错过了一些重要的事情.有人可以指出吗?
I suppose that I missed something important here. Can someone point it out?
这似乎仅在我调用dispatch_sync
而不是dispatch_async
时有效,但根据Brad dispatch_async
的介绍,此处的性能会更好.
It seems to work only when I call dispatch_sync
instead of dispatch_async
, but according to Brad dispatch_async
would give better performance here.
推荐答案
我不得不将代码结构更改为此:
I had to change the structure of the code to this:
- (void)renderFrame {
dispatch_async(drawingQueue, ^{
if (dispatch_semaphore_wait(frameRenderingSemaphore, DISPATCH_TIME_NOW) != 0) {
return;
}
@autoreleasepool {
// Drawing code...
}
dispatch_semaphore_signal(frameRenderingSemaphore);
});
}
以这种方式重组它后,dispatch_semaphore_wait
调用始终停止返回YES.我不确定这是否实际上只是在禁用Brad的信号灯等待技巧.但这有效.
After I restructured it this way, the dispatch_semaphore_wait
call stopped returning YES all the time. I am not sure if this is effectively just disabling Brad's semaphore wait trick or not. But it works.
这篇关于为什么即使我不滚动,dispatch_semaphore_wait()也会始终返回YES?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!