5

zacznę NSURLConnection w innym wątku:NSURLConnection rozpoczęto w innym wątku. Metody pełnomocnik nie nazywa

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

Ale moja metoda delegat nie nazywa się:

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

Po uruchomieniu w głównym wątku wszystko jest w porządku. Jak uruchomić połączenie w innym wątku i uzyskać wywoływanie metod delegatów w tym samym wątku?

+2

Roo, connectionWithRequest jest już asynchroniczne, nie musisz tego robić w dispatch_async. – Sebastian

+1

FYI, uruchamiasz też to połączenie dwa razy. Kiedy wywołujesz 'connectionWithRequest', to już uruchamia połączenie dla ciebie. Używaj 'start' tylko wtedy, gdy używasz opcji' startImmediately' opcji 'FALSE'. – Rob

Odpowiedz

5

GCD tworzy, niszczy, ponownie wykorzystuje wątki niejawnie i jest szansa, że ​​wątek zadzwonić początek od przestanie istnieć zaraz potem. Może to spowodować, że delegat nie otrzyma żadnych zwrotów.

Jeśli chciałbyś otrzymywać zwrotnego w wątku tła można użyć setDelegateQueue lub sendAsynchronousRequest:queue:completionHandler: metoda:

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

Najprostszym sposobem na rozpoczęcie NSURLConnection w wątku tła poprzez GCD jest:

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

Tak, to dobrze znane zachowanie NSURLConnection, ponieważ potrzebuje pętli uruchamiania do przetwarzania zdarzeń delegatów. Najczęstszym rozwiązaniem jest (a) tworzenie instancji za pomocą initWithRequest:delegate:startImmediately:, gdzie startImmediately jest FALSE; (b) ręcznie scheduleInRunLoop:forMode:, aby zaplanować go w pętli głównego uruchomienia; a następnie (c) start połączenie.

Ale, jak już masz tutaj, nie ma sensu wysyłać tego do kolejki tła, ponieważ jest już asynchroniczna, więc powinieneś po prostu zainicjować to z głównej kolejki i żadne z powyższych nie jest konieczne. Używasz powyższego wzorca w szczególnych przypadkach (np. Używasz podklasy NSOperation do zarządzania żądaniami), ale generalnie nie jest to konieczne.

Ponadto, FYI, skuteczne iOS9, NSURLConnection jest przestarzałe, więc powinieneś używać NSURLSession, tak czy inaczej. I NSURLSession nie podlega temu ograniczeniu.

1

Miałem podobny problem. Teraz zajmuję się żądaniem NSURLConnection w głównym wątku - działa on asynchronicznie, więc nie spowolni twojej aplikacji. W connectionDidFinishLoading uruchamiam następujący kod, aby przetworzyć wyniki moich połączeń. Wykonuję sprawdzenie, ponieważ mam wywołanie NSURLConnection, które może wyzwalać inne połączenia sieciowe. Ponieważ są już uruchomione w wątku w tle, nie chcę zaczynać nowego.

- (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]; 
    } 
} 
Powiązane problemy