2011-11-22 17 views
8

¿Cómo puedo obtener NSURLConnection para llamar a sus métodos delegados de un hilo diferente en lugar del hilo principal. Estoy tratando de perder el tiempo con el scheduleInRunLoop: forMode: pero no parece hacer lo que quiero.iOS, NSURLConnection: Delegar retrollamadas en hilo diferente?

Tengo que descargar un archivo grande e interrumpe el hilo principal con tanta frecuencia que algunas representaciones que se suceden comienzan a estar entrecortadas.

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

La otra cosa que no veo mucho es "Modos" Sólo hay dos modos documentados por lo que no es mucho realmente a prueba con.

¿Alguna idea?

Gracias

Respuesta

6

Hay varias opciones:

  1. En su aplicación de los métodos de delegado, hacer uso de dispatch_async.
  2. Inicie la programación de la conexión en un hilo de fondo.

Usted puede hacer esto último como esto:

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

Si quiere garantía en el que el hilo se está ejecutando, reemplace la llamada a dispatch_get_global_queue() adecuadamente.

+1

no se mantiene cerca del hilo en el que se ejecuta la cola? Entonces, llamo esto una vez, el hilo se mantiene. Llamo esto de nuevo, ya que GCD decide en qué hilo se ejecuta la cola, posiblemente se mantenga otro hilo y así sucesivamente ... Entonces, ¿no es esto posible mantener los hilos sin razón alguna una vez que se ha terminado el trabajo en los hilos utilizados? cola global? Además, ¿a qué te refieres con "Si quieres una garantía sobre qué hilo estás ejecutando, reemplaza la llamada a dispatch_get_global_queue() apropiadamente"? ¿Cómo se puede dirigir un hilo a través de GCD? – zumzum

0

Si realmente tiene que hacer la descarga en un nuevo hilo, puede ser más fácil de detachNewThreadSelector:toTarget:withObject:, configuración (y destruir) una NSAutoreleasePool, y luego usar uno de los selectores síncronos como NSData 's dataWithContentsOfURL: . Esto no hará uso de NSURLConnectionDelegate asincrónico.

Como esta llamada es síncrona, no volverá hasta que se haya descargado el archivo, lo que bloqueará el hilo principal, pero debido a que está en un hilo nuevo, no lo hará. Tenga en cuenta que esto suele ser un comportamiento desalentado. ¿Hay algún otro código en el hilo principal que se pueda optimizar?

+0

intentado. El archivo que estoy descargando es grande, así que tengo que escribirlo en el disco cuando está entrando. – gngrwzrd

0

NSURLConnection ya está realizando la descarga del hilo principal de forma asíncrona. Si entiendo su pregunta, ¿desea que los mensajes de los delegados se envíen en un hilo que no sea el hilo principal? No puede hacer eso ya que no puede modificar la implementación interna de NSURLConnection. Puedo pensar en dos formas de simular esto.

  1. Crear una sublcass de NSURLConnection (por ejemplo MyURLConnection) que asigna a sí mismo como propio delegado. Tenga en cuenta que esto crea un ciclo de retención intencional, así que tenga cuidado. MyURLConnection debe definir un nuevo delegate que admita NSURLConnectionDelegate. Llamemos a esto finalDelegate. Cuando MyURLConnection maneje sus propios mensajes de delegado, reenvíelos o llévelos al finalDelegate en el hilo que desee.

  2. Similar a la opción # 1 pero sin la subclase. Maneje los métodos de delegado NSURLConnection en el hilo principal y reenvíelos o envíelos al hilo que desee.

La principal diferencia es si usted quiere una subclase reutilizable que se comporte de esta manera o sea una implementación única.

EDIT: añadido sugerencia sobre cómo ejecutar código en el fondo

Si va a procesar la respuesta en el fondo me gustaría que desarrolla actividades de uso o gran despacho central. No hay necesidad de perder el tiempo con los bucles de ejecución y la creación de subprocesos. Echa un vistazo a Concurrency Programming Guide de Apple.

2

Si desea realizar descargas en un hilo separado, estoy bastante seguro de que estos son los robots que está buscando ...

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

Tiene un error tipográfico: NSMubaleURLRequest, debe ser NSMutableURLRequest – Borzh

+0

@Borzh, gracias! – Brooks

Cuestiones relacionadas