2012-03-29 13 views
13

Me pregunto si alguien puede explicar por qué enviando de vuelta a la cola principal y creando una repetición NSTimer ¿Tengo que agregarlo a RUN LOOP para que también se dispare? Incluso cuando utilizo performselectorOnMainThread, todavía tengo que agregarlo a un RUN LOOP para que se dispare.NSTimer requiriéndome que lo agregue a un runloop

A continuación se muestra un ejemplo de mi pregunta:

#define queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 
#define mainqueue dispatch_get_main_queue() 

- (void)someMethodBeginCalled 
{ 
    dispatch_async(queue, ^{ 
     int x = 0; 
     dispatch_async(mainqueue, ^(void){ 
      if([_delegate respondsToSelector:@selector(complete:)]) 
       [_delegate complete:nil]; 
     }); 
    }); 
} 

- (void)compelete:(id)object 
{ 
    [self startTimer]; 

    //[self performSelectorOnMainThread:@selector(startTimer) withObject:nil waitUntilDone:NO]; 
} 

- (void)startTimer 
{ 
    NSTimer timer = [NSTimer timerWithTimeInterval:3 target:self selector:@selector(callsomethingelse) userInfo:nil repeats:YES]; 

    //NSDefaultRunLoopMode 
    [[NSRunLoop currentRunLoop] addTimer:_busTimer forMode:NSRunLoopCommonModes]; 
} 

EDIT: creo redactado esta pregunta muy mal. Me gustaría saber por qué[[NSRunLoop currentRunLoop] addTimer:_busTimer forMode:NSRunLoopCommonModes]; es necesario en startTimer si llamo al someMethodBeginCalled. Si no incluyo esa línea, el temporizador no se dispara.

Si llamo a startTimer de viewDidLoad por ejemplo, puedo quitar la línea NSRunLoop y el temporizador se disparará cada 60 segundos.

Respuesta

12

Siempre se puede utilizar este método en su lugar:

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(getBusLocation) userInfo:nil repeats:YES];

esto le ahorrará una línea, ya que se sumará al bucle de ejecución automática.

+5

Este es el enfoque normal. Es raro agregar manualmente un temporizador a un runloop. En general, sin embargo, debe mantener el temporizador en un ivar para que pueda invalidarlo cuando sea necesario. –

+0

Sí, de lo contrario, el objeto al que llama nunca será desasignado si tiene un temporizador repetitivo. – borrrden

+0

He editado la pregunta, básicamente me pregunto por qué no puedo usar solo su línea cuando la inicializo desde dispatch_async en la cola principal. Sin la línea NSRunLoop, el temporizador no disparará. – chicken

3

Porque, como el docs dicen:

temporizadores trabajan en conjunto con los bucles de ejecución. Para utilizar un temporizador eficazmente, , debe tener en cuenta cómo funcionan los bucles de ejecución: consulte NSRunLoop y Threading Programming Guide. Tenga en cuenta en particular que los bucles de ejecución retienen sus temporizadores, por lo que puede liberar un temporizador después de haberlo agregado a un ciclo de ejecución .

Es una decisión de diseño que Apple tomó cuando escribieron el código para NSTimer (y estoy seguro de que tenían una buena razón para hacerlo) y no hay nada que podamos hacer para evitarlo. ¿Es realmente así de gravoso?

+7

Para ser claros: NSTimers se implementan como parte del ciclo de ejecución. Una de las fuentes de ejecución de bucle es "¿hay NSTimers pendientes que deban activarse?" Un NSTimer es solo algunos datos que se cuelga en un runloop. Esto es algo muy bueno, porque significa que los temporizadores no requieren hilos. –

18

Y aquí es cómo agregar un NSTimer a un runloop:

NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
[runLoop addTimer:timer forMode:NSDefaultRunLoopMode]; 
+1

El OP está preguntando el motivo para agregar un temporizador al ciclo de ejecución, en lugar de cómo agregar un temporizador al ciclo de ejecución . – chengsam

2

Como @sosborn dijo, NSTimer s dependen de NSRunLoop s, y puesto que las colas GCD crear hilos que no tienen ejecutar bucles, NSTimer doesn No juegue bien con GCD.

Compruebe hacia fuera esta otra pregunta StackOverflow sobre el asunto: Is it safe to schedule and invalidate NSTimers on a GCD serial queue?

para resolver ese problema, implementado MSWeakTimer: https://github.com/mindsnacks/MSWeakTimer (y tenía la implementación revisado por un ingeniero libdispatch en la última WWDC!)

+0

Supongo que querías decir que _NSTimer no funciona bien con ** Colas GCD ** _, ¿verdad? – 0xced

+0

¡Correcto! Arreglé esto. –

0

Adición el temporizador para el runloop no funcionó en mi caso. Tuve que crear el temporizador en el hilo principal. Estaba haciendo esta creación de subprocesos en un delegado de MultipeerConnectivity.

dispatch_async(dispatch_get_main_queue(), ^{ 
     self.timer = [NSTimer scheduledTimerWithTimeInterval:self.interval invocation: self.invocation repeats:YES]; 
    }); 
0

método de temporizador no se llamará desde colas GCD crear hilos que no se han ejecutado bucles

dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_HIGH, 0),^{ [NSTimer scheduledTimerWithTimeInterval: 1 repite: SÍ bloque:^(NSTimer * _Nonnull timer) { NSLog (@ "Método de temporizador de la cola principal de GCD"); }];

});

Sin embargo, cuando se envía a la cola principal, se llamará al método del temporizador, ya que se agregará al ciclo principal de ejecución de subprocesos.

dispatch_async (dispatch_get_main_queue(),^{ [NSTimer scheduledTimerWithTimeInterval: 1 repite: SÍ bloque:^(temporizador NSTimer * _Nonnull) { NSLog (@ "método de temporizador de GCD cola principal"); }];

});