2011-12-07 14 views
12

Ho scoperto un grosso problema con CADisplayLink.Come interrompere e riprendere correttamente un CADisplayLink?

Ho l'EAGLLayer più semplice con OpenGL ES 1.1 che disegna un triangolo rotante per il test. Questo ha bisogno di un metodo ciclo corsa per essere chiamato a frequenza di aggiornamento dello schermo, in modo da avviare il runloop in questo modo:

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

Quando i lanci di applicazione di test, mi chiamano -startRunloop. Quando tocco lo schermo, chiamo -stopRunloop. Quando tocco di nuovo, chiamo -startRunloop. E così via. Ping Pong.

Sto misurando la frequenza con cui il metodo -drawFrame viene chiamato in 20 secondi e NSLog.

  • Il primo ciclo di avvio/arresto funziona sempre al 100%. Ottengo il frame rate massimo.

  • Tutti i cicli di avvio/arresto SUBSEQUENT mostrano solo circa l'80% delle prestazioni. Ottengo un frame rate significativamente più piccolo. Ma: sempre quasi esattamente lo stesso, +/- 2 fotogrammi. Senza tendenza a degradare ulteriormente anche dopo altri 50 cicli di avvio/arresto.

In conclusione: la creazione di un CADisplayLink come faccio io sopra va bene, fino a quando è invalidata o in pausa. Dopodiché, qualsiasi nuovo CADisplayLink non funziona più bene. Anche se è stato creato nuovo e nello stesso identico modo di prima. Lo stesso è vero se sospendo/riprendo chiamando il metodo -setPaused: con YES/NO.

Mi sono assicurato che con Allocations e VM Tracker Instruments non ci sia alcun problema di gestione della memoria. Ho anche verificato che il metodo -invalidate di CADisplayLink venga davvero chiamato.

iOS 4.0 sul dispositivo (iPhone 4).

Perché è quello? Mi sto perdendo qualcosa?

+0

suona come un bug. Penso che tu debba presentare una segnalazione di bug ad Apple. –

+0

Ho lo stesso problema. Non ho bisogno che il DisplayLink funzioni sempre, ma sembra che non abbia una scelta. Quindi ora sto usando solo flag nel selettore del gestore invece di usare isPaused. –

risposta

1

Si crea una nuova istanza di collegamento di visualizzazione ad ogni chiamata di avvio. Hai provato a riutilizzare la stessa istanza?

Inoltre, è sempre possibile sospendere il collegamento del display.

5

Sto usando

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

vedere se funziona per voi

5

io pensi che cosa si vuole veramente è semplicemente quello di mettere in pausa e riattivare il tuo link di visualizzazione.

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

Prova questo a Swift,

displayLink?.remove(from: RunLoop.current, forMode: RunLoopMode.defaultRunLoopMode) 
Problemi correlati