当滚动视图滚动时,Brad Larson为CADisplayLink
冻结问题提供了solution。
我的OpenGL ES绘制方法由CADisplayLink
调用,我尝试了Brad的技术但无法使其工作。核心问题是我的OpenGL ES视图由UIScrollView
托管,当U IScrollView
滚动时,CADisplayLink
停止发射。
Brad描述的技术应该让CADisplayLink
在滚动期间继续激活(通过将其添加到NSRunLoopCommonModes
而不是默认的runloop模式),并使用花哨的信号量欺骗渲染回调应该确保当UIKit太占用时它不会呈现。
问题是,无论如何,信号量技巧都会阻止渲染回调。
首先,我在我的OpenGL ES视图的initWithFrame
方法中创建串行GCD队列和信号量(在主线程上):
frameRenderingQueue = dispatch_queue_create("com.mycompany.crw", DISPATCH_QUEUE_SERIAL);
frameRenderingSemaphore = dispatch_semaphore_create(1);
创建显示链接并将其添加到NSRunLoopCommonModes
:
CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(renderFrame)];
[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
渲染回调执行Brad的技术:
- (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
,因此渲染回调永远不会呈现。即使我不滚动。
我想我错过了一些重要的事情。有人能说出来吗?
修改:它似乎仅在我拨打dispatch_sync
而不是dispatch_async
时才有效,但根据布拉德dispatch_async
会在此处提供更好的效果。
答案 0 :(得分:0)
我必须将代码的结构更改为:
- (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的信号量等待技巧。但它确实有效。