2011-11-22 12 views
8

Come posso ottenere NSURLConnection per chiamare i suoi metodi delegate da un thread diverso anziché il thread principale. Sto cercando di scherzare con il scheduleInRunLoop: forMode: ma non sembra fare ciò che voglio.iOS, NSURLConnection: Delega i callback su thread diversi?

Devo scaricare un file di grandi dimensioni e interrompe il thread principale così frequentemente che un po 'di rendering che sta accadendo inizia a diventare instabile.

NSURLRequest * request = [NSURLRequest requestWithURL:url]; 
NSURLConnection * connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; 
NSRunLoop * loop = [NSRunLoop currentRunLoop]; 
NSLog(@"loop mode: %@",[loop currentMode]); 
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 
[connection start]; 

L'altra cosa che non vedo molto di è "Modalità" Ci sono solo due modi documentati in modo da non molto in realtà alla prova con.

Qualche idea?

Grazie

risposta

6

Ci sono diverse opzioni:

  1. Nell'implementazione dei metodi delegato, fare uso di dispatch_async.
  2. Avviare la pianificazione della connessione su un thread in background.

Si può fare il secondo in questo modo:

// all the setup comes here 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    NSRunLoop *loop = [NSRunLoop currentRunLoop]; 
    [connection scheduleInRunLoop:loop forMode:NSRunLoopCommonModes]; 
    [loop run]; // make sure that you have a running run-loop. 
}); 

Se si desidera una garanzia su cui filo si sta eseguendo, sostituire la chiamata a dispatch_get_global_queue() in modo appropriato.

+1

non si occupa del thread su cui gira la coda? Quindi, lo chiamo una volta, il thread è tenuto in giro. Lo chiamo di nuovo, dal momento che GCD decide su quale thread gira la coda, quindi forse un altro thread viene tenuto in giro e così via ... Quindi, non è possibile mantenere i thread in giro senza motivo una volta che il lavoro è stato fatto sui thread usati. coda globale? Inoltre cosa intendi per "Se vuoi una garanzia su quale thread stai correndo, sostituisci la chiamata a dispatch_get_global_queue() in modo appropriato."? Come puoi indirizzare un thread attraverso GCD? – zumzum

0

Se veramente bisogno di fare il download di un nuovo thread, può essere più facile da detachNewThreadSelector:toTarget:withObject:, messa a punto (e distruggere) un NSAutoreleasePool, e quindi utilizzare uno dei selettori sincrone come NSData s' dataWithContentsOfURL: . Questo non farà uso dello NSURLConnectionDelegate asincrono.

Poiché questa chiamata è sincrona, non verrà restituita fino a quando il file non sarà stato scaricato, il che bloccherà il thread principale, ma poiché si è in una nuova discussione, non lo sarà. Si noti che questo è in genere un comportamento scoraggiato. C'è altro codice che sta accadendo nel thread principale che può essere ottimizzato?

+0

provato. Il file che sto scaricando è di grandi dimensioni, quindi ho bisogno di scriverlo sul disco mentre sta arrivando. – gngrwzrd

0

NSURLConnection sta già eseguendo il download fuori dal thread principale in modo asincrono. Se capisco la tua domanda, vorresti che i messaggi delegati vengano inviati su un thread diverso dal thread principale? Non è possibile farlo poiché non è possibile modificare l'implementazione interna di NSURLConnection. Posso pensare a due modi per simulare questo.

  1. Creare un sublcass di NSURLConnection (ad esempio MyURLConnection) che si assegna come proprio delegato. Nota che questo crea un ciclo di conservazione intenzionale, quindi fai attenzione. MyURLConnection dovrebbe definire un nuovo delegate che supporta NSURLConnectionDelegate. Chiamiamo questo finalDelegate. Quando MyURLConnection gestisce i propri messaggi delegati, inoltrati o li invii a finalDelegate su qualsiasi thread che ti piace.

  2. Simile all'opzione 1 ma senza sottoclasse. Gestire i metodi delegati NSURLConnection sul thread principale e inoltrarli/inviarli a qualsiasi thread desiderato.

La differenza principale è che se si vuole una sottoclasse riutilizzabile che si comporta in questo modo o si tratta di un'una tantum implementazione.

EDIT: suggerimento aggiunto su come eseguire il codice in background

Se avete intenzione di elaborare la risposta in background che sarebbe o operazioni di uso o grande spedizione centrale. Non c'è bisogno di scherzare con i loop di esecuzione e la creazione di thread. Dai un'occhiata a Apple Concurrency Programming Guide.

2

Se si desidera eseguire download su un thread separato, sono abbastanza sicuro che questi sono i droidi che state cercando ...

- (void) dispatchRequest{ 
    self->finished = NO; 
    NSMutableURLRequest* request = //Formulate your request 
    NSThread* download_thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadThreadLoop:) object:request]; 
    [download_thread start]; 
} 
- (void) downloadThreadLoop:(NSMutableURLRequest*) request{ 

    NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; 

    while(!self->finished]){ 
     //This line below is the magic! 
     [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
    } 
} 

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{ 
    //... 
} 

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{ 
    //... 
} 

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{ 
    //... 
} 

- (void)connectionDidFinishLoading:(NSURLConnection *)connection{ 
    //... 
    self->finished = YES; 
} 
+0

Hai un errore di battitura: NSMubaleURLRequest, dovrebbe essere NSMutableURLRequest – Borzh

+0

@Borzh, grazie! – Brooks

Problemi correlati