Fondamentalmente non si hanno garanzie con NSTimer
o dispatch_after
; programmano il codice da attivare sul thread principale, ma se qualcos'altro richiede molto tempo per essere eseguito e blocca il thread principale, il timer non scatterà.
Detto questo, è possibile evitare facilmente il blocco del thread principale (utilizzare solo I/O asincrono) e le cose dovrebbero essere piuttosto buone.
Non si dice esattamente ciò che è necessario fare nel codice del timer, ma se tutto ciò che si deve fare è visualizzare un conto alla rovescia, si dovrebbe andare bene finchè si calcola il tempo SMPTE in base all'ora del sistema, e non il numero di secondi che secondo te dovrebbe essere trascorso in base all'intervallo del timer. Se lo fai, quasi sicuramente andrai alla deriva e non sarai più sincronizzato con il tempo reale. Invece, si noti il tempo di inizio e poi fare tutti i calcoli in base a quanto segue:
// Setup
timerStartDate = [[NSDate alloc] init];
[NSTimer scheduledTimer...
- (void)timerDidFire:(NSTimer *)timer
{
NSTImeInterval elapsed = [timerStartDate timeIntervalSinceNow];
NSString *smtpeCode = [self formatSMTPEFromMilliseconds:elapsed];
self.label.text = smtpeCode;
}
Ora si visualizzerà il codice di tempo corretto non importa quante volte il timer viene licenziato. (Se il timer non si attiva abbastanza spesso, il timer non si aggiorna, ma quando si aggiorna sarà accurato. Non sarà mai fuori sincrono.)
Se si utilizza CADisplayLink, verrà chiamato il metodo veloce come il display si aggiorna. In altre parole, veloce come sarebbe utile, ma non più veloce. Se stai visualizzando il tempo, questa è probabilmente la strada da percorrere.
Si noti che _frameInterval_ era obsoleto in iOS 10.0, utilizzare _preferredFramesPerSecond_, in questo modo: 'displayLink.preferredFramesPerSecond = 30.0;' per 30 fps – WongWray