5

inizio un NSURLConnection in un altro thread:NSURLConnection è stato avviato in un'altra discussione. metodi delegato non chiamati

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), 
     ^{ 
      NSURLConnection *connection = [NSURLConnection connectionWithRequest:[request preparedURLRequest] delegate:self]; 
      [connection start]; 
     }); 

Ma il mio metodo delegato non viene chiamato:

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData*)data; 

quando eseguito su tutto il thread principale va bene. Come posso eseguire la connessione su un altro thread e ottenere i metodi delegate chiamati allo stesso thread?

+2

Roo, connectionWithRequest è già asincrono, non è necessario dispatch_async. – Sebastian

+1

FYI, stai anche iniziando questa connessione due volte. Quando chiami 'connectionWithRequest', sta già iniziando la connessione per te. Usa 'start' solo quando usi l'opzione' startImmediately' di 'FALSE'. – Rob

risposta

5

GCD crea, distrugge, riutilizza le discussioni implicitamente e c'è una possibilità che il filo si chiama partenza da smetterà esistente subito dopo. Ciò potrebbe causare il delegato che non riceve alcuna richiamata.

Se desiderate ricevere richiamata in thread in background, è possibile utilizzare setDelegateQueue o sendAsynchronousRequest:queue:completionHandler: metodo:

NSURLConnection* connection = [[NSURLConnection alloc] initWithRequest:request 
                  delegate:self 
                startImmediately:NO]; 
[connection setDelegateQueue:[[NSOperationQueue alloc] init]]; 
[connection start]; 

Il modo più semplice per iniziare NSURLConnection in thread in background tramite GCD è:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), 
       ^{ 
        NSURLResponse* response = nil; 
        NSError* error = nil; 
        [NSURLConnection sendSynchronousRequest:request] returningResponse:&response error:&error]; 
        NSLog(@"%@", response); 
       }); 
2

Sì, questo è un comportamento noto di NSURLConnection perché richiede un ciclo di esecuzione per elaborare gli eventi delegati. La soluzione più comune è (a) istanziarla con initWithRequest:delegate:startImmediately: dove startImmediately è FALSE; (b) manualmente scheduleInRunLoop:forMode: per programmarlo nel ciclo di esecuzione principale; e quindi (c) start la connessione.

Ma, come lo avete qui, non ha senso spedirlo a una coda in secondo piano, poiché è già asincrono, quindi dovreste semplicemente iniziarlo dalla coda principale e nessuno dei precedenti è necessario. Si utilizza il modello sopra in casi speciali (ad esempio, si stava utilizzando la sottoclasse NSOperation per gestire le richieste), ma in genere non è necessario.

Inoltre, FYI, efficace iOS9, NSURLConnection è obsoleto, quindi è necessario utilizzare NSURLSession, comunque. E NSURLSession non ha questa limitazione.

1

Ho avuto un problema simile. Quello che sto facendo ora è eseguire la richiesta NSURLConnection nel thread principale - è in esecuzione in modo asincrono in modo da non rallentare l'applicazione. In connectionDidFinishLoading, eseguo il seguente codice per elaborare i risultati delle mie chiamate. Eseguo il controllo perché ho la chiamata NSURLConnection che può attivare altre chiamate di rete. Dato che sono già in esecuzione su un thread in background, non voglio iniziarne uno nuovo.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    if ([NSThread isMainThread]) { 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ 
     //Background Thread 
     [self processFinishLoading:connection]; 
     }); 
    } 
    else { 
     [self processFinishLoading:connection]; 
    } 
}