5

Ho un ciclo for che voglio aggiungere un ritardo tra le iterazioni. Ho cambiato waitUntilDone su SÌ e ottenere gli stessi risultati. La mia serie ha solo due numeri in esso ed entrambi sono chiamati dopo i cinque secondi invece di:Objective C per il ritardo del loop

0s - niente 5s - blocco chiamato 10s- blocco chiamato

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 

Sto usando Cocos2d se quello che conta

+0

Utilizzando un 'NSTimer' è anche buona soluzione. – zaph

+0

@zaph NSTimer non funziona bene con cocos2d o SpriteKit. Preferisci i metodi built-in 'schedule' forniti da CCNode e tutte le sue classi derivate. – YvesLeBorg

risposta

4

Il ciclo for verrà inviato uno dopo l'altro in modo che si ritardi sostanzialmente per lo stesso tempo.
Invece impostare un diverso crescente ritardo per ogni:

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]; 

       }); 
} 
+1

Funziona perfettamente! Grazie! – Asdrubal

+0

Funziona come una magia !! Votato .. – NSPratik

1

@zaph ha una buona soluzione. Ho pensato di provare da un'angolazione diversa. Poiché Objective-C è Obiettivo -C, perché non definire un qualche tipo di oggetto per eseguire questo ciclo temporizzato? Suggerimento: questo esiste. Possiamo usare NSTimer e la sua proprietà userInfo per risolvere questo problema. Penso che la soluzione sia una specie di elegante, se non un brutto scherzo.

// 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]; 
    } 
} 

Vorrei verificare che il NSTimer venga mantenuto aggiungendolo al ciclo di esecuzione. Se questo non è il caso, dovresti memorizzare un riferimento ad esso come una proprietà su qualunque classe stia gestendo tutto questo.

Vale anche la pena notare che poiché NSTimers viene installato sul loop principale per impostazione predefinita, non è necessario preoccuparsi di tutte le cose GCD. Poi di nuovo, se questo lavoro è un lavoro piuttosto difficile, potresti voler -processNextTransaction: scaricare il suo lavoro su un'altra coda GCD e poi tornare alla coda principale per inizializzare l'istanza di NSTimer.

Assicurarsi di utilizzare il metodo -scheduledTimer...; I metodi di classe timer... su NSTimer non lo installano su alcun ciclo e gli oggetti siedono semplicemente nello spazio senza fare nulla. Non fare lo repeats:YES, sarebbe tragico, dato che avresti timer collegati al ciclo di esecuzione, volenti o nolenti, senza riferimenti che li indichino per sapere come o dove fermarli. Questa è generalmente una brutta cosa.

Per evitare le eccezioni EXC_BAD_ACCESS, non deallocare mai l'oggetto il cui metodo è NSTimer chiamare, se il timer non è ancora stato attivato. È possibile archiviare lo NSTimer in sospeso in una proprietà della classe in modo da poter gestire questo tipo di cose. Se si tratta di un ViewController che sta gestendo tutto questo (che in genere è), quindi vorrei utilizzare il seguente codice per ripulire il timer su -viewWillDisappear. (Questo presuppone che si sta impostando un nuovo timer per qualche @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. 
    } 
} 
+0

Grazie per aver preso il timer per fornire una soluzione diversa e spiegarlo bene. Lo apprezzo. – Asdrubal

+1

Ovviamente! Rispondere alle domande in modo approfondito è un buon modo per assicurarmi di rimanere nitido, quindi lo considero un vantaggio. – josefdlange