2011-12-07 9 views
12

Descubrí un gran problema con CADisplayLink.Cómo detener y reanudar correctamente un CADisplayLink?

Tengo el EAGLLayer más básico con OpenGL ES 1.1 dibujando un triángulo giratorio para probar. Esto necesita un método de bucle de ejecución que se llamará a una tasa de refresco de pantalla, por lo que se inicia la runloop así:

- (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; 
    } 
} 

Cuando se inicie la aplicación de prueba, me llaman -startRunloop. Cuando toco la pantalla, llamo -stopRunloop. Cuando toco nuevamente, llamo -startRunloop. Etcétera. Ping pong.

Estoy midiendo con qué frecuencia se llama al método -drawFrame en 20 segundos y NSLog it.

  • El PRIMER ciclo de arranque/parada funciona siempre al 100%. Obtengo la velocidad de cuadros máxima.

  • Todos los ciclos de arranque/parada SUBSECUENTES solo muestran aproximadamente el 80% del rendimiento. Obtengo una velocidad de cuadros significativamente menor. Pero: siempre casi exactamente lo mismo, +/- 2 cuadros. Sin tendencia a degradarse aún después de 50 ciclos más de arranque/parada.

En conclusión: la creación de un CADisplayLink como yo anteriormente está muy bien, hasta que sea invalidada o en pausa. Después de eso, cualquier nuevo CADisplayLink ya no funciona bien. Incluso si se crea nuevo y de la misma manera que antes. Lo mismo es cierto si hago una pausa/reanudar llamando al método -setPaused: con SÍ/NO.

Me he asegurado con las asignaciones y los instrumentos de seguimiento de VM que no hay problemas de administración de memoria. También he comprobado que el método de invalidación de CADisplayLink realmente se llama.

iOS 4.0 en el dispositivo (iPhone 4).

¿Por qué es eso? ¿Me estoy perdiendo de algo?

+0

suena como un error. Creo que debes presentar un informe de error a Apple. –

+0

Tengo el mismo problema. No necesito que DisplayLink se ejecute todo el tiempo, pero parece que no tengo otra opción. Así que ahora solo estoy usando banderas en el selector de controlador en lugar de usar isPaused. –

Respuesta

1

Crea una nueva instancia de enlace de pantalla con cada llamada de inicio. ¿Has intentado solo reutilizar la misma instancia?

Además, siempre puede pausar el enlace de visualización.

5

estoy usando

[displayLink removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 

ver si funciona para usted

5

que usted piensa que lo que realmente quiere es simplemente para hacer una pausa y pausa de su enlace de visualización.

- (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; 
} 
0

Prueba esto en Swift,

displayLink?.remove(from: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode) 
Cuestiones relacionadas