miércoles, 24 de julio de 2013

Descarga asíncrona de imágenes desde una URL

Una de las reglas que debes seguir a rajatabla en la descarga de datos es la siguiente:
"Las descargas de datos siempre serán ASÍNCRONAS"
Si yo fuese responsable de la contratación de algún desarrollador no haría las estúpidas preguntas a las que estamos acostumbrados como ¿ Cuánto te gustaría ganar? o  ¿ Cómo te ves dentro de 5 años? . Sin embargo, cogería un Mac, abriría el XCode y pediría que me hiciese una descarga de datos a través de alguna petición http. Si el candidato escribiese el siguiente código y me dijese que ya está hecho, la entrevista terminaría en ese preciso instante.

NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.ohmyapps.es/images/xxxxxx.xxx"]];

Como no quiero escribir artículos largos dejaré para otro día el artículo acerca de NSURLConnection para descargas asíncronas y me centraré en un código que aparece a menudo en diferentes búsquedas por la red y puede resultar algo complicado ya que utiliza la tecnología de GCD (Grand Central Dispatch) para dispositivos multinúcleos y bloques. Este código sólo es válido para aplicaciones superiores a iOS 4.x (aunque ya no creo que nadie desarrolle para esas versiones). Deberemos seguir los siguientes pasos:

1. Copiamos el siguiente código en el archivo de cabecera:


void UIImageFromURL(NSURL * URL, void (^imageBlock)(UIImage * image), void (^errorBlock)(void));

2. Copiamos el siguiente código en el archivo de implementación:


void UIImageFromURL(NSURL * URL, void (^imageBlock)(UIImage * image), void (^errorBlock)(void) )
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^(void)
        {
            NSData * data = [[NSData alloc] initWithContentsOfURL:URL];
            UIImage * image = [[UIImage alloc] initWithData:data];
            dispatch_async( dispatch_get_main_queue(), ^(void){
                if( image != nil )
                {
                    imageBlock( image );
                }
                else
                {
                    errorBlock();
                }
            });
        });
}

Algún observador dirá ,"Pero si utilizas el mismo código que dices que no se debe utilizar nunca", a lo cual yo contestaré, sí pero con la salvedad de el método dispatch_async(dispatch_queue_t queue, ^(void)block);. Y qué hace este método os preguntaréis. Pues simplemente le pasa un bloque de código para su ejecución asíncrona en una cola. 

3. Finalmente utilizamos el método donde lo necesitemos


UIImageFromURL( [NSURL URLWithString:@"http://www.ohmyapps.es/images/xxxxxx.xxx"], ^( UIImage * image )
                   {
                       //Aquí ejecutamos lo que queramos con nuestra imagen
                   }, ^(void){
                       NSLog(@"error!");
                       //Bloque para ejecutar en caso de error
                   });
    }


Para las próximas entradas veremos otra manera de descarga de datos asíncrona y el uso de alguna librería interesante.

2 comentarios:

  1. Buenos días Manuel, he llegado al blog a partir de LinkedIn, y ya me ha picado la curiosidad.

    De las mejores explicaciones que he visto sobre este tema "hoygan"!!

    Simplemente bravo jeje. Un saludo!!

    ResponderEliminar
    Respuestas
    1. Pues muchas gracias. Espero sacar tiempo y seguir publicando artículos.
      Un saludo.

      Eliminar