6

Lavorando con un po 'di codice, mi imbatto in loop di esecuzione, di cui sono nuovo, all'interno di NSOperation s.Utilizzo di NSThread sleep in una NSOperation

Gli NSOperation s sono occupati a scaricare dati e, mentre sono occupati, c'è il codice per attendere il completamento del download, sotto forma di NSRunLoop se thread sleep.

Questo codice, in particolare, è di interesse per me:

while (aCertainConditionIsTrue && [self isCancelled]==NO) { 
    if(![[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]){ 
     [NSThread sleepForTimeInterval:1.0]; 
    } 
} 

ho letto sui cicli visione e runMode:beforeDate: aspetteranno per una sorgente d'ingresso o di un timeout. Anche se non sono al 100% ciò che conta come input souce.

Alla prima esecuzione di questo restituisce sempre NO e raggiunge lo sleepForTimeInterval:. È cattivo?

In una particolare classe di utilità, colpisce lo sleepForTimeInterval: molto - una volta per ogni thread - che danneggia significativamente le prestazioni.

Qualche soluzione migliore per questo o un consiglio?

risposta

2

Dormire blocca la filettatura. Forse cambi il tuo codice per usare performSelector: withObject: afterDelay. In questo modo il tuo thread può continuare a funzionare.

... 
    done = NO; 
    [self checkDoneCondition:nil]; 
    ... 

- (void)checkDoneCondition:(id)object { 
    if (aCertainConditionIsTrue && [self isCancelled]==NO) { 
     if(...) { 
      [self performSelector:@selector(checkDoneCondition:) withObject:[con error] afterDelay:1.0]; 
     } else { 
      done = YES; 
     } 
    } 
} 
1

Sembra che è necessario utilizzare un concomitante NSOperation. Ecco la parte rilevante nella documentazione di Apple:

A differenza di un'operazione non concorrente, che gestisce in modo sincrono, un mascherato corre in modo asincrono. In altre parole, quando si chiama il metodo di avvio di un'operazione simultanea, tale metodo può restituire prima che l'attività corrispondente sia completata. Questo potrebbe accadere perché l'oggetto operazione ha creato un nuovo thread per eseguire l'attività o perché l'operazione ha chiamato una funzione asincrona. Non importa se l'operazione è in corso quando il controllo ritorna a il chiamante, solo che potrebbe essere in corso. (...) In un'operazione concomitante, il metodo di avvio è responsabile di che avvia l'operazione in modo asincrono. Se si genera un thread o si chiama una funzione asincrona, lo si fa da questo metodo. All'avvio dell'operazione, il metodo di avvio dovrebbe anche aggiornare lo stato di esecuzione dell'operazione come riportato dal metodo isExecuting . A tale scopo, invii notifiche KVO per il percorso chiave Esegui , che consente ai clienti interessati di sapere che l'operazione è in esecuzione. Il metodo isExecuting deve anche restituire lo stato in modalità thread-safe.

(da https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html)

In altre parole, è possibile eseguire l'override del metodo -start nella sottoclasse NSOperation, e hanno Ivar per la proprietà executing e finished. Questo metodo avvierà il download in un thread separato. All'avvio del download, imposta il flag executing e attiva KVO.Quando è finito in questo thread, fai lo stesso con finished e executing. Sembra complicato ma in realtà è piuttosto semplice.

Vedere anche questa domanda su Stack Overflow con una spiegazione grande: Subclassing NSOperation to be concurrent and cancellable