2011-11-22 11 views
8

W jaki sposób można uzyskać NSURLConnection do wywoływania jego delegatów metod z innego wątku zamiast wątku głównego. Próbuję zadziwić się z scheduleInRunLoop: forMode: ale nie wydaje się robić to, co chcę.iOS, NSURLConnection: Delegować oddzwonienia na inny wątek?

Muszę pobrać duży plik i tak często przerywa wątek główny, że niektóre renderowania zaczynają robić się niepewne.

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]; 

Inna sprawa, nie widzę dużo jest „Tryby” Istnieją tylko dwa tryby udokumentowane tak naprawdę nie wiele do testowania z.

Wszelkie pomysły?

Dzięki

Odpowiedz

6

Istnieje kilka opcji:

  1. W implementacji metod delegata wykorzystują dispatch_async.
  2. Rozpocznij harmonogram połączenia z wątkiem tła.

Można zrobić to ostatnie tak:

// 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. 
}); 

Jeśli chcesz gwarancję na który wątek używasz wymienić wezwanie do dispatch_get_global_queue() odpowiednio.

+1

nie trzyma się wokół wątku, w którym działa kolejka? Tak więc, nazywam to raz, wątek jest trzymany w pobliżu. Nazywam to jeszcze raz, ponieważ GCD decyduje o tym, w jakim wątku działa kolejka, to może pozostać inny wątek i tak dalej ... Czyż nie jest to możliwe, aby utrzymać wątki bez powodu, gdy praca zostanie wykonana na wątkach? globalna kolejka? Co masz na myśli, mówiąc: "Jeśli chcesz gwarancji na wątek, który używasz, zastąp wywołanie odpowiednio dispatch_get_global_queue()."? W jaki sposób możesz celować w wątek poprzez GCD? – zumzum

0

Jeśli naprawdę trzeba zrobić odsyłacz w nowym wątku, może łatwiej będzie detachNewThreadSelector:toTarget:withObject:, konfiguracji (i niszczenia) NSAutoreleasePool, a następnie użyć jednego z synchronicznymi selektorów jak NSData „s dataWithContentsOfURL: . To nie będzie korzystać z asynchronicznego NSURLConnectionDelegate.

Ponieważ to połączenie jest synchroniczne, nie powróci, dopóki plik nie zostanie pobrany, co zablokuje główny wątek, ale ponieważ jesteś w nowym wątku, nie będzie. Pamiętaj, że jest to zazwyczaj zachowanie odradzane. Czy istnieje inny kod w głównym wątku, który można zoptymalizować?

+0

Tried to. Plik, który pobierałem, jest duży, więc muszę go zapisać na dysku, ponieważ nadchodzi. – gngrwzrd

0

NSURLConnection wykonuje asynchroniczne pobieranie głównego wątku. Jeśli rozumiem twoje pytanie, czy chcesz, aby wiadomości delegatów były wysyłane w wątku innym niż główny wątek? Nie możesz tego zrobić, ponieważ nie możesz zmodyfikować wewnętrznej implementacji NSURLConnection. Mogę wymyślić dwa sposoby symulacji tego.

  1. Tworzenie sublcass z NSURLConnection (np MyURLConnection), które przypisuje się jako własne pełnomocnika. Zauważ, że tworzy to celowy cykl utrzymania, więc bądź ostrożny. MyURLConnection powinien zdefiniować nowy delegate, który obsługuje NSURLConnectionDelegate. Nazwijmy to finalDelegate. Gdy MyURLConnection obsługuje własne wiadomości delegatów, przesyłaj je dalej lub wysyłaj do finalDelegate w dowolnym wątku.

  2. Podobny do opcji nr 1, ale bez podklasy. Obsługuj metody delegatów NSURLConnection w głównym wątku i przesyłaj dalej/wysyłaj je do dowolnego wątku.

Główna różnica polega na tym, że podklasa wielokrotnego użytku ma się zachowywać w ten sposób lub jest to jednorazowa implementacja.

EDIT: dodano sugestii, w jaki sposób uruchomić kod w tle

Jeśli zamierzamy przetwarzać odpowiedź w tle bym albo operacji mechanicznych lub Grand Central Dispatch. Nie musisz się martwić pętlami uruchamiania i tworzeniem wątków. Sprawdź Apple Concurrency Programming Guide.

2

Jeśli chcesz aby pobieranie na osobnym wątku, jestem całkiem pewny, że są to roboty których szukasz ...

- (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

Masz literówkę: NSMubaleURLRequest, powinno być NSMutableURLRequest – Borzh

+0

@Borzh, dzięki! – Brooks

Powiązane problemy