¿Puedo cargar un UIImage desde una URL?

134

Tengo una URL para una imagen (la obtuve de UIImagePickerController) pero ya no tengo la imagen en la memoria (la URL se guardó de una ejecución anterior de la aplicación). ¿Puedo volver a cargar el UIImage desde la URL?

Veo que UIImage tiene una imageWithContentsOfFile: pero tengo una URL. ¿Puedo usar dataWithContentsOfURL de NSData para leer la URL?

EDITAR1


basado en la respuesta de @ Daniel intenté el siguiente código pero no funciona ...

NSLog(@"%s %@", __PRETTY_FUNCTION__, photoURL);     
if (photoURL) {
    NSURL* aURL = [NSURL URLWithString:photoURL];
    NSData* data = [[NSData alloc] initWithContentsOfURL:aURL];
    self.photoImage = [UIImage imageWithData:data];
    [data release];
}

Cuando lo ejecuté, la consola muestra:

-[PhotoBox willMoveToWindow:] file://localhost/Users/gary/Library/Application%20Support/iPhone%20Simulator/3.2/Media/DCIM/100APPLE/IMG_0004.JPG
*** -[NSURL length]: unrecognized selector sent to instance 0x536fbe0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL length]: unrecognized selector sent to instance 0x536fbe0'

Mirando la pila de llamadas, llamo a URLWithString, que llama a URLWithString: relativeToURL :, luego initWithString: relativeToURL :, luego _CFStringIsLegalURLString, luego CFStringGetLength, luego forwarding_prep_0 , luego reenvío , luego - [NSObject doesNleReco.

¿Alguna idea de por qué mi NSString (la dirección de photoURL es 0x536fbe0) no responde a la longitud? ¿Por qué dice que no responde a [longitud NSURL]? ¿No sabe que param es un NSString, no un NSURL?

EDIT2


OK, el único problema con el código es la conversión de cadena a URL. Si codifico la cadena, todo lo demás funciona bien. Entonces, algo está mal con mi NSString y si no puedo resolverlo, supongo que debería ser una pregunta diferente. Con esta línea insertada (pegué la ruta desde el registro de la consola anterior), funciona bien:

photoURL = @"file://localhost/Users/gary/Library/Application%20Support/iPhone%20Simulator/3.2/Media/DCIM/100APPLE/IMG_0004.JPG";
programador
fuente
Parece que photoURL ya es un NSURL, no un NSString, dado que NSLog lo manejó.
dibujado
@drawn: Parece un error en los documentos. Dice que UIImagePickerControllerMediaURL es un NSString pero en realidad es un objeto NSURL.
programa
La biblioteca DLImageLoader es INCREÍBLE. sólido como una roca, sin doco, un comando y todo es perfecto. Que hallazgo.
Fattie
Yo segundo (tercero?) DLImageLoader. Era escéptico sobre si los comentarios al respecto en esta página eran objetivos, pero lo intenté de todos modos y funciona muy bien. Tengo un UIImageView dentro de un UITableViewCell. Todo lo que hice fue reemplazar el UIImageView con un DLImageView, luego llamé imageFromUrl: método para cargar la imagen, y todo funciona: carga asíncrona, almacenamiento en caché, etc. No podría ser más fácil.
itnAAnti
DLImageLoader sigue siendo fantástico, otro bueno es Haneke , aunque sufre un poco por no mantenerse del todo.
Fattie

Respuestas:

319

Puede hacerlo de esta manera (sincrónicamente, pero compacto):

UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:MyURL]]];

Un enfoque mucho mejor es usar LazyTableImages de Apple para preservar la interactividad.

Daniel Blezek
fuente
1
¿No es necesario convertir los datos del formato de archivo PNG (o JPG) a datos UIImage? ¿O UIImage lo descubre de alguna manera?
programa
2
Supongo que debería simplemente RTFM, dice directamente en UIImage Class Reference qué formatos de archivo puede admitir e imageWithData: dice que pueden ser datos de un archivo, parece que debería funcionar.
programa
@Daniel: no funcionó, edité mi pregunta para incluir mi código real y la información de excepción. Es un poco extraño.
programa
@Daniel: funciona si uso una constante de cadena en lugar del NSString que estaba pasando. Así que este último problema fue algo incorrecto en mi NSString, no un problema con el código NSURL / NSData / UIImage que funciona. Gracias Daniel!
programa
Si está utilizando solo una imagen y está buscando una solución rápida, puede escribir un poco de código que almacena en caché la imagen individual.
MrDatabase
27

Puede probar SDWebImage , proporciona:

  1. Carga asincrónica
  2. Almacenamiento en caché para uso sin conexión
  3. Coloque la imagen del titular para que aparezca mientras se carga
  4. Funciona bien con UITableView

Ejemplo rápido:

    [cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
Muhammad Hassan Nasr
fuente
2
Modifiqué un poco esa biblioteca y la integré con UIImage + Resize para agregarle las capacidades Resize / Crop. Si lo necesita, échele
Tony
1
Este ejemplo completa a UIImageView. SDWebImageTambién le permite llenar un UIImagedirectamente usando SDWebImageManager - (void) downloadWithURL:.... Vea su ejemplo en el archivo Léame.
bendytree
10

Y la versión rápida:

   let url = NSURL.URLWithString("http://live-wallpaper.net/iphone/img/app/i/p/iphone-4s-wallpapers-mobile-backgrounds-dark_2466f886de3472ef1fa968033f1da3e1_raw_1087fae1932cec8837695934b7eb1250_raw.jpg");
    var err: NSError?
    var imageData :NSData = NSData.dataWithContentsOfURL(url,options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &err)
    var bgImage = UIImage(data:imageData)
usuario3763002
fuente
7

Si usted está realmente , absolutamente positivamente seguro de que el NSURL es una dirección de fichero, es decir, [url isFileURL]está garantizado para devolver cierto en su caso, a continuación, sólo tiene que utilizar:

[UIImage imageWithContentsOfFile:url.path]
Dhiraj Gupta
fuente
7

obtenga DLImageLoader e intente seguir el código

   [DLImageLoader loadImageFromURL:imageURL
                          completed:^(NSError *error, NSData *imgData) {
                              imageView.image = [UIImage imageWithData:imgData];
                              [imageView setContentMode:UIViewContentModeCenter];

                          }];

Otro ejemplo típico del mundo real del uso de DLImageLoader, que puede ayudar a alguien ...

PFObject *aFacebookUser = [self.fbFriends objectAtIndex:thisRow];
NSString *facebookImageURL = [NSString stringWithFormat:
    @"http://graph.facebook.com/%@/picture?type=large",
    [aFacebookUser objectForKey:@"id"] ];

__weak UIImageView *loadMe = self.userSmallAvatarImage;
// ~~note~~ you my, but usually DO NOT, want a weak ref
[DLImageLoader loadImageFromURL:facebookImageURL
   completed:^(NSError *error, NSData *imgData)
    {
    if ( loadMe == nil ) return;

    if (error == nil)
        {
        UIImage *image = [UIImage imageWithData:imgData];
        image = [image ourImageScaler];
        loadMe.image = image;
        }
    else
        {
        // an error when loading the image from the net
        }
    }];

Como mencioné anteriormente, otra gran biblioteca para considerar en estos días es Haneke (desafortunadamente no es tan liviana).

Muruganandham K
fuente
1
SDWebImage es la biblioteca más popular en Objective-C y KingFisher es el puerto Swift.
XY
1
Es cierto, ¡pero DLImageLoader es mejor! :)
Fattie
5

Pruebe este código, puede configurar la carga de la imagen con él, para que los usuarios sepan que su aplicación está cargando una imagen desde la URL:

UIImageView *yourImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"loading.png"]];
    [yourImageView setContentMode:UIViewContentModeScaleAspectFit];

    //Request image data from the URL:
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://yourdomain.com/yourimg.png"]];

        dispatch_async(dispatch_get_main_queue(), ^{
            if (imgData)
            {
                //Load the data into an UIImage:
                UIImage *image = [UIImage imageWithData:imgData];

                //Check if your image loaded successfully:
                if (image)
                {
                    yourImageView.image = image;
                }
                else
                {
                    //Failed to load the data into an UIImage:
                    yourImageView.image = [UIImage imageNamed:@"no-data-image.png"];
                }
            }
            else
            {
                //Failed to get the image data:
                yourImageView.image = [UIImage imageNamed:@"no-data-image.png"];
            }
        });
    });
Jouhar
fuente
2
He preferido esta solución ya que no requiere cargar o no un marco de 3 ª parte o crear instancias de colas de carga de datos, etc.
BillyRayCyrus
4

Echa un vistazo a lo AsyncImageViewprovisto aquí . Algún buen código de ejemplo, e incluso podría ser utilizable "listo para usar" para usted.

marcc
fuente
Ejemplo interesante, es muy similar en concepto al ejemplo de Apple LazyTableImages mencionado en la respuesta anterior.
programa
Es similar, pero tenga en cuenta que AsyncImageView realmente no funciona en tablas, al menos no cuando recicla las celdas de la tabla (como debería).
n13
4

AFNetworking proporciona carga de imagen asíncrona en un UIImageView con soporte de marcador de posición. También admite redes asíncronas para trabajar con API en general.

pauliephonic
fuente
3

Asegúrese de habilitar esta configuración desde iOS 9:

Configuración de seguridad de transporte de aplicaciones en Info.plist para garantizar la carga de la imagen desde la URL de modo que permita descargar la imagen y configurarla.

ingrese la descripción de la imagen aquí

Y escribe este código:

NSURL *url = [[NSURL alloc]initWithString:@"http://feelgrafix.com/data/images/images-1.jpg"];
NSData *data =[NSData dataWithContentsOfURL:url];
quickViewImage.image = [UIImage imageWithData:data];
Nagarjun
fuente
2

La forma de usar una extensión Swift para UIImageView(código fuente aquí ):

Crear propiedad calculada para asociados UIActivityIndicatorView

import Foundation
import UIKit
import ObjectiveC

private var activityIndicatorAssociationKey: UInt8 = 0

extension UIImageView {
    //Associated Object as Computed Property
    var activityIndicator: UIActivityIndicatorView! {
        get {
            return objc_getAssociatedObject(self, &activityIndicatorAssociationKey) as? UIActivityIndicatorView
        }
        set(newValue) {
            objc_setAssociatedObject(self, &activityIndicatorAssociationKey, newValue, UInt(OBJC_ASSOCIATION_RETAIN))
        }
    }

    private func ensureActivityIndicatorIsAnimating() {
        if (self.activityIndicator == nil) {
            self.activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.Gray)
            self.activityIndicator.hidesWhenStopped = true
            let size = self.frame.size;
            self.activityIndicator.center = CGPoint(x: size.width/2, y: size.height/2);
            NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                self.addSubview(self.activityIndicator)
                self.activityIndicator.startAnimating()
            })
        }
    }

Inicializador personalizado y Setter

    convenience init(URL: NSURL, errorImage: UIImage? = nil) {
        self.init()
        self.setImageFromURL(URL)
    }

    func setImageFromURL(URL: NSURL, errorImage: UIImage? = nil) {
        self.ensureActivityIndicatorIsAnimating()
        let downloadTask = NSURLSession.sharedSession().dataTaskWithURL(URL) {(data, response, error) in
            if (error == nil) {
                NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                    self.activityIndicator.stopAnimating()
                    self.image = UIImage(data: data)
                })
            }
            else {
                self.image = errorImage
            }
        }
        downloadTask.resume()
    }
}
fpg1503
fuente
0

La mejor y más fácil forma de cargar la imagen a través de la URL es mediante este código:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    NSData *data =[NSData dataWithContentsOfURL:[NSURL URLWithString:imgUrl]];

    dispatch_async(dispatch_get_main_queue(), ^{
        imgView.image= [UIImage imageWithData:data];
    });
});

Reemplazar imgUrlpor su ImageURL
Reemplazar imgViewpor su UIImageView.

Cargará la imagen en otro subproceso, por lo que no ralentizará la carga de su aplicación.

jalmatari
fuente