objective-c ios nsurlconnection grand-central-dispatch

objective c - NSURLConnection vs. NSData+GCD



objective-c ios (3)

NSData siempre ha tenido un método muy conveniente llamado +dataWithContentsOfURL:options:error: Si bien es conveniente, también bloquea la ejecución del subproceso actual, lo que significa que era básicamente inútil para el código de producción (ignorando NSOperation ). Utilicé este método con poca frecuencia, olvidé por completo que existía. Hasta hace poco.

La forma en que he estado capturando datos de los tubos es el enfoque estándar de NSURLConnectionDelegate : escriba una clase de descarga que maneje los distintos métodos de NSURLConnectionDelegate , acumule gradualmente algunos datos, maneje errores, etc. para tantas solicitudes como sea posible.

Digamos que mi clase de descargador típico se ejecuta en algún lugar en el estadio de 100 líneas. NSData 100 líneas para hacer de forma asíncrona lo que NSData puede hacer de forma sincrónica en una línea. Para una mayor complejidad, la clase descargadora necesita un protocolo delegado propio para comunicar la finalización y los errores a su propietario, y el propietario debe implementar ese protocolo de alguna manera.

Ahora, ingrese a Grand Central Dispatch, y puedo hacer algo tan increíblemente simple como:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { NSData* data = [NSData dataWithContentsOfURL:someURL]; // Process data, also async... dispatch_async(dispatch_get_main_queue(), ^(void) { // Back to the main thread for UI updates, etc. }); });

Y puedo tirar esa ventosa en cualquier lugar que quiera, justo en línea. No necesita una clase de descarga, no necesita manejar métodos de delegado de conexión: datos asíncronos fáciles en solo unas pocas líneas. La disparidad entre este enfoque y mi enfoque pre-GCD es de una magnitud lo suficientemente grande como para activar la Alarma Demasiado buena para ser verdadera.

Por lo tanto, mi pregunta: ¿existen advertencias sobre el uso de NSData + GCD para tareas simples de descarga de datos en lugar de NSURLConnection (asumiendo que no me interesan las cosas como el progreso de la descarga)?


A partir de OS X v10.9 y iOS 7, la forma preferida es utilizar NSURLSession . Le brinda una interfaz agradable basada en bloques y funciones como la cancelación, suspensión y descarga en segundo plano.


Estás perdiendo mucha funcionalidad aquí:

  • No se puede seguir la progresión de la descarga.
  • No se puede cancelar la descarga.
  • No se puede gestionar el posible proceso de autenticación.
  • No puede manejar los errores fácilmente, lo que es muy importante, especialmente en el desarrollo móvil, como en el iPhone, por supuesto (porque a menudo pierde su red en condiciones reales, por lo que es muy importante hacer un seguimiento de estos casos de errores de red cuando se desarrolla para iOS)

y probablemente hay más, supongo.

El enfoque correcto para eso es crear una clase que administre la descarga.

Ver mi propia clase OHURLLoader , por ejemplo, que es simple e hice que la API fuera fácil de usar con bloques:

NSURL* url = ... NSURLRequest* req = [NSURLRequest requestWithURL:url]; OHURLLoader* loader = [OHURLLoader URLLoaderWithRequest:req]; [loader startRequestWithCompletion:^(NSData* receivedData, NSInteger httpStatusCode) { NSLog(@"Download of %@ done (statusCode:%d)",url,httpStatusCode); if (httpStatusCode == 200) { NSLog(%@"Received string: %@", loader.receivedString); // receivedString is a commodity getter that interpret receivedData using the TextEncoding specified in the HTTP response } else { NSLog(@"HTTP Status code: %d",httpStatusCode); // Log unexpected status code } } errorHandler:^(NSError *error) { NSLog(@"Error while downloading %@: %@",url,error); }];

Consulte el OHURLLoader y el proyecto de muestra en github para obtener más información.

De esta manera:

  • aún confía en los métodos asíncronos proporcionados por NSURLConnection (y como la documentación de Apple dice acerca de la Programación concurrente si ya existe una API para realizar tareas asíncronas, úsela en lugar de confiar en otra tecnología de subprocesamiento si es posible)
  • conserva las ventajas de NSURLConnection (manejo de errores, etc.)
  • Pero también tiene las ventajas de la sintaxis de los bloques que hace que su código sea más legible que cuando utiliza métodos de delegado.

Videos de la Sesión WWDC 2010 :

  • WWDC 2010 Session 207 - Aplicaciones de red para iPhone OS, Parte 1
  • WWDC 2010 Session 208 - Aplicaciones de red para iPhone OS, Parte 2

El profesor dijo

"Los hilos son malos".

Para la programación en red, se recomienda encarecidamente usar API asíncrona con RunLoop.

Porque, si usa NSData + GCD como el siguiente, usa un hilo por conexión.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { NSData* data = [NSData dataWithContentsOfURL:someURL];

Y es probable que use muchas conexiones y muchos hilos. Es demasiado fácil de usar GCD :-) Luego, muchos hilos comen una gran cantidad de memoria para su pila. Por lo tanto, sería mejor usar una API asíncrona como dijo AliSoftware.