Почему dispatch_semaphore_wait() возвращает ДА ​​все время, даже если я не прокручиваю?

Брэд Ларсон поставил решение для проблемы с замораживанием CADisplayLink при прокрутке прокрутки.

Мой метод рисования OpenGL ES вызывается CADisplayLink, и я попробовал технику Брэда, но не могу заставить его работать. Основная проблема заключается в том, что мое представление OpenGL ES размещено UIScrollView, а когда свитки U IScrollView, CADisplayLink останавливает стрельбу.

Предполагается, что описанная технология Brad должна продолжать CADisplayLink даже во время прокрутки (добавив ее к NSRunLoopCommonModes вместо режима runloop по умолчанию) и используя причудливый трюк семафора, который должен обеспечить обратный вызов рендеринга что он не отображается, когда UIKit слишком занят.

Проблема заключается в том, что трюк семафора предотвращает обратный вызов рендеринга, независимо от того, что.

Во-первых, я создаю серийную GCD-очередь и семафор в методе initWithFrame моего представления OpenGL ES, как это (в основном потоке):

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];

Обратный вызов рендера выполняет технику Брэда:

- (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, но в соответствии с Brad dispatch_async здесь будет лучше работать.

Ответ 1

Мне пришлось изменить структуру кода на это:

- (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 или нет. Но он работает.