Почему UIScrollView приостанавливает мой CADisplayLink?

У меня есть вид, поддерживаемый CAEAGLLayer, который находится внутри UIScrollView. Когда я начинаю прокрутку, CADisplayLink, вызывающий метод -draw openGL, перестает получать вызов.

Я проверил, что мои методы запуска/остановки runloop не вызываются при прокрутке. Метод -draw просто не вызывается, как только начинается прокрутка, и возобновляет вызов, как только прокрутка заканчивается.

Устанавливает ли UIKit запуск CADisplayLink при запуске прокрутки?

Ссылка на отображение добавляется в цикл выполнения следующим образом:

[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

Возможно, существует конфликт с этим режимом цикла запуска и UIScrollView? Существуют ли другие режимы цикла запуска или альтернативные решения, позволяющие запускать CADisplayLink даже при прокрутке UIScrollView?

Я думал, что в любом приложении может быть больше одного CADisplayLink. Это неправильно?

Ответ 1

Вы не находитесь в NSDefaultRunLoopMode, прокручивая UIScrollView; вы находитесь в UITrackingRunLoopMode. Таким образом, любой таймер, запланированный только для первого, не будет срабатывать в последнем. Вы можете добавить свои CADisplayLink в несколько режимов цикла цикла, нажимая addToRunLoop:forMode: несколько раз или вызывать его один раз с помощью NSRunLoopCommonModes, который охватывает оба режима.

Об этом подробно рассказано и о других проблемах с интеграцией прокрутки с GL на WWDC 2012 на Сессию 223: "Повышение удобства пользователей с помощью прокрутки"; Я рекомендую смотреть video, так как там есть много других вещей, которые могут иметь отношение к вашей ситуации.


Пример в (2016) Swift3...

let d = CADisplayLink(target: self, selector: #selector(ThisClassName.updateAlpha))
d.add(to: RunLoop.current, forMode: RunLoopMode.commonModes)


//and then, for example...
func updateAlpha() {
  let a = leader.layer.presentation()?.value(forKey: "opacity") as! CGFloat
  follower.alpha = a
  }