本文介绍了为什么即使我不滚动,dispatch_semaphore_wait()也会始终返回YES?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

布拉德·拉森(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?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 07:43