Что заставляет CADisplayLink запускаться только время от времени / задерживаться?

Может быть, вам не нужна вся эта информация, чтобы помочь мне с этой проблемой. Основные вопросы: что может вызвать CADisplayLink отложить стрельбу, и как проверить на возможные причины?

Я использую CADisplayLink таймер скорости / прокрутки по инерции - моя собственная реализация представления формы звукового сигнала:

- (void) startVelocityScrollTimer {
    dispatch_sync(dispatch_get_main_queue(), ^{
        if (_velocityScrollTimer == nil) {
            _velocityScrollTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(velocityScroll)];
            _velocityScrollTimer.frameInterval = 1;
            [_velocityScrollTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        }
    });
}

У меня проблемы с точностью таймера. Обычно он срабатывает 50 или 60 раз в секунду (не уверен, но здесь точное значение не имеет значения). Во время определенных действий эта скорость снижается до 3–5 пожаров в секунду, что слишком мало для плавной прокрутки. Я не могу определить причину этих задержек.

Я пробовал:

  • Полностью отсоединение чертежа и загрузки с помощью аутсорсинга загрузки аудиоданных в выделенную очередь отправки, которая загружает данные асинхронно.
  • Профилирование и оптимизация метода рисования. На пиках это занимает максимум 6 мс.
  • Профилирование метода, вызываемого при срабатывании таймера (speedScroll:). Выполнение обычно занимает менее 1 мс, иногда пики достигают 3 мс.
  • с помощью NSRunLoopCommonModes вместо NSDefaultRunLoopMode для CADisplayLink таймер

В кешировании у меня много dispatch_sync и несколько dispatch_barrier_sync. Хотя большинство из них не имеет значения, я

  • профилировать каждую отправку время начала в моем кэшировании
  • профилируется каждый раз выполнения отправленных блоков в кешировании

Хотя большинство из них должны быть неактуальными. Я не нашел ожиданий / блокировок, которые занимали более 50 мс. Это немного медленно, но все же я думаю, что таймер не должен опускаться до 5 срабатываний в секунду или хуже.

Для профилирования я не использовал инструмент профилирования (не мог их обработать). Вместо этого я использовал типичный подход:

double start = CACurrentMediaTime();

// code to profile here

NSLog(@"it took %.2fms", (CACurrentMediaTime() - start) * 1000);

Вот метод, выполняемый при срабатывании таймера. Три метода в середине - это в основном простые простые вычисления позиции, которые выполняются практически мгновенно, за исключением последнего, который выполняет dispatch_sync для главной очереди. Тем не менее, это завершается очень быстро (менее 3 мс, см. Выше).

- (void) velocityScroll {
    Float32 cyclesPerSecond = 1.0 / _velocityScrollTimer.duration;

    [self applyScrollVelocityToScrollPosition:cyclesPerSecond];
    [self applyScrollVelocityDecelerationToScrollVelocity:cyclesPerSecond];
    [self ensureVelocityScrollOnlyActiveIfNeeded];

    [self setNeedsDisplay];
}

Я знаю, что вы, ребята, хотели бы видеть больше кода, но кода много, и я не хочу публиковать его все. Пожалуйста, попросите отдельные детали, которые я опубликую здесь, если они вам нужны.

Что может вызвать задержки между пожарами CADisplayLink таймер или как это узнать?

0 ответов

Другие вопросы по тегам