Как правильно остановить и возобновить CADisplayLink?
Я понял большую проблему с CADisplayLink.
У меня есть самый простой EAGLLayer с OpenGL ES 1.1, рисующий вращающийся треугольник для тестирования. Для этого требуется метод цикла выполнения, который вызывается при частоте обновления экрана, поэтому я запускаю runloop следующим образом:
- (void)startRunloop {
if (!animating) {
CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(drawFrame)];
[dl setFrameInterval:1.0];
[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
self.displayLink = dl;
animating = YES;
}
}
- (void)stopRunloop {
if (animating) {
[self.displayLink invalidate];
self.displayLink = nil;
animating = NO;
}
}
Когда запускается тестовое приложение, я вызываю -startRunloop.
Когда я нажимаю экран, я вызываю -stopRunloop.
Когда я снова нажимаю, я вызываю -STARTRunloop. И так далее. Пинг-понг.
Я измеряю, как часто вызывается метод -drawFrame через 20 секунд, и NSLog it.
-
ПЕРВЫЙ цикл запуска/остановки всегда выполняется на 100%. Я получаю максимальную частоту кадров.
-
Все циклы запуска/остановки SUBSEQUENT показывают только около 80% производительности. Я получаю значительно меньшую частоту кадров. Но: всегда почти то же самое, +/- 2 кадра. Без тенденции к дальнейшему ухудшению даже после еще 50 циклов старта/остановки.
В заключение: СОЗДАНИЕ CADisplayLink, как я делаю выше, в порядке, пока он не будет признан недействительным или приостановлен. После этого любой новый CADisplayLink больше не работает. Даже если он создал новый и точно так же, как раньше. То же самое верно, если я приостанавливаю/возобновляю его, вызывая метод -setPaused: с YES/NO.
Я уверен, что с Allocations и VM Tracker Instruments нет проблемы с управлением памятью. Я также проверил, что метод -invalidate CADisplayLink действительно вызван.
iOS 4.0 на устройстве (iPhone 4).
Почему? Я что-то пропустил?
Ответы
Ответ 1
Я думаю, что вы действительно хотите просто приостановить и отключить свою ссылку на изображение.
- (void)createRunloop {
CADisplayLink *dl = [[UIScreen mainScreen] displayLinkWithTarget:self selector:@selector(drawFrame)];
[dl setFrameInterval:1.0];
[dl addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
self.displayLink = dl;
// start in running state, your choice.
dl.paused = NO;
}
- (void)startRunloop {
self.displayLink.paused = NO;
}
- (void)stopRunloop {
self.displayLink.paused = YES;
}
- (void)destroyRunloop {
[self.displayLink invalidate];
self.displayLink = nil;
}
Ответ 2
Я использую
[displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
посмотреть, работает ли он для вас
Ответ 3
Вы создаете новый экземпляр ссылки на изображение с каждым стартовым вызовом. Вы пытались просто повторно использовать один и тот же экземпляр?
Кроме того, вы всегда можете просто приостановить отображение ссылки.
Ответ 4
Попробуйте это в Swift,
displayLink?.remove(from: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode)
Ответ 5
Для Swift 4.2
displayLink.remove(from: RunLoop.current, forMode: RunLoop.Mode.common)