9

Ho creato una sottoclasse NSOperation per gestire alcune operazioni di archivio zip. Non importa cosa, se sovrascrivo -start o -main questo blocco di codice avviene sempre:NSOperation non sta accadendo nella thread in background

if ([NSThread isMainThread]) { 
    NSLog(@"I am in the main thread"); 
    return; 
} 

Qualsiasi idea di cosa sta succedendo?

Ho provato ad aggiungere questo blocco:

- (void) start { //also tried overriding main 

    if ([NSThread isMainThread]) { 
     NSLog(@"In main thread, trying again"); 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
      [self start]; 
     }); 
     return; 
     //hard working code etc... 
     //cpu intensive zip operations... 
    } 

Ma questo provoca un incidente, un EXC_BAD_ACCESS violazione indicando la linea di dispatch_async.

+0

Forse sto semplicemente fraintendendo questo, ma sembra che avrai un ciclo infinito nel tuo blocco, perché stai chiamando start from inside itself. Stai aggiungendo l'nsoperation a una coda, o stai chiamando start te stesso? –

+2

@BenPious non è un ciclo infinito, perché quando viene chiamato dall'interno di 'dispatch_async', la condizione (' [NSThread isMainThread] ') sarà falsa. –

+2

Puoi mostrare (a) la creazione del tuo 'NSOperationQueue'; e (b) l'aggiunta di queste operazioni al tuo 'NSOperationQueue'? Se li "avviano manualmente", saranno sul thread principale, ma se li aggiungi a "NSOperationQueue" che crei, non dovrebbero. Secondo [documenti] (http://developer.apple.com/library/ios/documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html#//apple_ref/doc/uid/TP40004591-RH2-SW15) " quando chiamate il metodo 'start' di un'operazione non simultanea direttamente dal vostro codice, l'operazione viene eseguita immediatamente nel thread corrente." – Rob

risposta

7

Non importa cosa, se sovrascrivo -start o -Main questo blocco di codice sempre accade:

La coda principale operazione viene eseguito sul thread principale. Da documenti per +[NSOperationQueue mainQueue]:

La coda restituita esegue operazioni sul thread principale. Il ciclo di esecuzione principale del thread controlla i tempi di esecuzione di queste operazioni.

Quindi, l'esecuzione in un altro thread dipende dalla coda a cui si aggiunge l'operazione, non da come si scrive il codice dell'operazione. Se si desidera che il funzionamento di girare su una coda diversa operazione, è necessario creare una coda dei vostri stessi utilizzando

NSOperationQueue* aQueue = [[NSOperationQueue alloc] init]; 

È possibile trovare un esempio nel Adding Operations to an Operation Queue nella Guida concorrenza di programmazione.

Ma questo causa un arresto anomalo, una violazione EXC_BAD_ACCESS che punta alla riga dispatch_async.

Suona come -[NSOperation start] probabilmente non è rientrante. Il tuo codice esegue in modo efficace lo stesso metodo su due thread differenti. Infatti, guarda the docs for -start, è ovvio che il codice non funziona:

È possibile chiamare questo metodo in modo esplicito se si desidera eseguire i vostri operazioni manualmente. Tuttavia, è un errore del programmatore chiamare questo metodo su un oggetto operazione che si trova già in una coda di operazioni o per accodare l'operazione dopo aver chiamato questo metodo. Dopo aver aggiunto un oggetto operativo a una coda, la coda si assume la piena responsabilità di . [Enfasi aggiunta. -Caleb]

In altre parole, non lo facciamo.

+1

Penso che la risposta non sia una spiegazione del problema dell'OP. Formare il codice parziale dato del metodo 'start' sovrascritto che sembra _perfettamente _ bene per quanto riguarda il rientro. Se il metodo 'start' di NSOperation è rientrante o no è irrilevante - poiché NON DEVE essere chiamato comunque (ad esempio tramite' [super start] '(e dal codice dato, non lo farà). Se l'operazione è avviata _manuale_ E iniziato dall'accodamento di esso in un 'NSOperationQueue' NON è asserito dall'OP. Quindi il tuo testo enfatizzato dai documenti potrebbe essere solo un suggerimento di un potenziale problema – CouchDeveloper

+1

Dal punto di vista del design, ha anche perfettamente senso incapsulare il "contesto di esecuzione" (ad esempio la coda) nell'operazione asincrona e rendere tale _private_. Un client di una funzione asincrona in genere non deve specificare il contesto di esecuzione su cui viene eseguita tale operazione (diversamente da un possibile gestore di completamento in cui il client può specificare l'esecuzione contesto) – CouchDeveloper

+1

Holy Crap guys, non intendevo postare questa domanda, l'ho digitato, ma poi l'ho risolto da solo, eseguivo le operazioni attraverso il mainQueue. chiuso il browser senza inviarlo, ma devo averlo inviato. – Justin