objective-c for-loop cocos2d-iphone delay grand-central-dispatch

objective c - Objetivo C para retardo de bucle



objective-c for-loop (2)

Tengo un ciclo for que quiero agregar un retraso entre iteraciones. He cambiado waitUntilDone a YES y obtengo los mismos resultados. Mi matriz solo tiene dos números y se llaman a los dos después de los cinco segundos en lugar de:

0s - nada 5s - Bloque llamado 10s - Bloque llamado

for(NSNumber* transaction in gainsArray) { double delayInSeconds = 5.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { NSLog(@"Block"); [self performSelectorOnMainThread:@selector(private_addTransactionToBankroll:) withObject:transaction waitUntilDone:NO]; }); } 2015-06-16 20:11:06.485 TestApp[97027:6251126] Block 2015-06-16 20:11:06.485 TestApp[97027:6251127] Block

Estoy usando Cocos2d si eso importa


@zaph tiene una solución bastante buena. Pensé que lo intentaría desde un ángulo diferente. Como Objective-C es Objective -C, ¿por qué no definir algún tipo de objeto para hacer este bucle cronometrado? Sugerencia: esto existe. Podemos usar NSTimer y su propiedad userInfo para resolver esto. Creo que la solución es algo elegante, si no un hack desagradable.

// Somewhere in code.... to start the ''loop'' NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self action:@selector(processNextTransaction:) userInfo:@{ @"gains": [gainsArray mutableCopy] } repeats:NO]; // What handles each ''iteration'' of your ''loop'' - (void)processNextTransaction:(NSTimer *)loopTimer { NSMutableArray *gains = [loopTimer.userInfo objectForKey:@"gains"]; if(gains && gains.count > 0) { id transaction = [gains firstObject]; [gains removeObjectAtIndex:0]; // NSMutableArray should really return the object we''re removing, but it doesn''t... [self private_addTransactionToBankroll:transaction]; NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self action:@selector(processNextTransaction:) userInfo:@{ @"gains": gains } repeats:NO]; } }

Verificaría que el NSTimer se conserve al agregarlo al ciclo de ejecución. Si ese no es el caso, debe almacenar una referencia como propiedad en cualquier clase que administre todo esto.

También vale la pena señalar que debido a que los NSTimers se instalan en el ciclo de ejecución principal de forma predeterminada, no es necesario preocuparse por todo el material de GCD. Por otra parte, si este trabajo es bastante difícil, es posible que desee -processNextTransaction: descargar su trabajo en otra cola GCD y luego volver a la cola principal para inicializar la instancia NSTimer.

Asegúrese de utilizar el método -scheduledTimer... ; timer... los métodos de clase en NSTimer no lo instalan en ningún ciclo, y los objetos simplemente se quedan en el espacio sin hacer nada. No hagas repeats:YES , eso sería trágico, ya que tendrías temporizadores conectados al ciclo de ejecución de cualquier manera, sin referencias que los señalaran para saber cómo o dónde detenerlos. Esto es generalmente algo malo.

Para evitar excepciones de EXC_BAD_ACCESS , nunca desloque el objeto cuyo método va a llamar un NSTimer , si ese temporizador no se ha NSTimer aún. Es posible que desee almacenar el NSTimer pendiente en una propiedad de su clase para que pueda manejar este tipo de cosas. Si se trata de un ViewController que está gestionando todo esto (que normalmente es), entonces usaría el siguiente código para limpiar el temporizador en -viewWillDisappear . (Esto supone que está configurando un nuevo temporizador en algún @property , self.timer )

- (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if(self.timer) { [self.timer invalidate]; // -invalidate removes it from the run loop. self.timer = nil; // Stop pointing at it so ARC destroys it. } }


El bucle for enviará uno justo después del otro, de modo que esencialmente se retrasarán por el mismo tiempo.
En cambio, establezca un retraso creciente diferente para cada uno:

double delayInSeconds = 0.0; for(NSNumber* transaction in gainsArray) { delayInSeconds += 5.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { NSLog(@"Block"); [self performSelectorOnMainThread:@selector(private_addTransactionToBankroll:) withObject:transaction waitUntilDone:NO]; }); }