Posso caricare un UIImage da un URL?


134

Ho un URL per un'immagine (ottenuto da UIImagePickerController) ma non ho più l'immagine in memoria (l'URL è stato salvato da una precedente esecuzione dell'app). Posso ricaricare nuovamente UIImage dall'URL?

Vedo che UIImage ha un imageWithContentsOfFile: ma ho un URL. Posso usare dataWithContentsOfURL di NSData: per leggere l'URL?

EDIT1


basato sulla risposta di @ Daniel ho provato il seguente codice ma non funziona ...

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

Quando l'ho eseguito la console mostra:

-[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'

Guardando lo stack di chiamate, sto chiamando URLWithString, che chiama URLWithString: relativeToURL :, quindi initWithString: relativeToURL :, quindi _CFStringIsLegalURLString, quindi CFStringGetLength, quindi forwarding_prep_0 , quindi inoltro , quindi - [NSObjectSN).

Qualche idea sul perché il mio NSString (l'indirizzo di photoURL è 0x536fbe0) non risponda alla lunghezza? Perché dice che non risponde a - [lunghezza NSURL]? Non sa che param è un NSString, non un NSURL?

EDIT2


OK, l'unico problema con il codice è la conversione da stringa a URL. Se codifico la stringa, tutto il resto funziona bene. Quindi qualcosa non va nel mio NSString e se non riesco a capirlo, suppongo che dovrebbe andare come una domanda diversa. Con questa riga inserita (ho incollato il percorso dal registro della console sopra), funziona benissimo:

photoURL = @"file://localhost/Users/gary/Library/Application%20Support/iPhone%20Simulator/3.2/Media/DCIM/100APPLE/IMG_0004.JPG";

Sembra che photoURL sia già un NSURL, non un NSString, dato che NSLog lo ha gestito.
disegnato

@drawn: sembra un errore nei documenti. Dice che UIImagePickerControllerMediaURL è un NSString ma in realtà è un oggetto NSURL.
progrmr

La libreria DLImageLoader è INCREDIBILE. solido, senza doco, un comando e tutto è perfetto. Che scoperta.
Fattie,

Io secondo (terzo?) DLImageLoader. Ero scettico sul fatto che i commenti al riguardo in questa pagina fossero obiettivi - ma l'ho provato comunque e funziona molto bene. Ho un UIImageView all'interno di un UITableViewCell. Tutto quello che ho fatto è stato sostituire UIImageView con un DLImageView, quindi chiamato imageFromUrl: metodo per caricare l'immagine, e tutto funziona semplicemente - caricamento asincrono, memorizzazione nella cache, ecc. Non potrebbe essere più semplice.
itnAAnti

DLImageLoader rimane fantastico, un altro buono è Haneke , anche se soffre un po 'di non essere del tutto mantenuto.
Fattie,

Risposte:


319

Puoi farlo in questo modo (in modo sincrono, ma compatto):

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

Un approccio molto migliore consiste nell'utilizzare LazyTableImages di Apple per preservare l'interattività.


1
I dati non devono essere convertiti dal formato di file PNG (o JPG) in dati UIImage? O UIImage lo capisce in qualche modo?
progrmr

2
Immagino che dovrei solo RTFM, dice proprio in UIImage Class Reference quali formati di file può supportare e imageWithData: dice che possono essere dati da un file, sembra che dovrebbe funzionare.
progrmr

@Daniel: non ha funzionato, ho modificato la mia domanda per includere il mio codice attuale e le informazioni sull'eccezione. È un po 'bizzarro.
progrmr

@Daniel: funziona se uso una costante di stringa anziché l'NSString in cui stavo passando. Quindi questo ultimo problema era qualcosa di sbagliato nel mio NSString, non un problema con il codice NSURL / NSData / UIImage che funziona. Grazie Daniel!
progrmr

Se stai utilizzando solo un'immagine e stai cercando una soluzione rapida, puoi semplicemente scrivere un po 'di codice che memorizza nella cache l'immagine singola.
MrDatabase,

27

Puoi provare SDWebImage , che fornisce:

  1. Caricamento asincrono
  2. Memorizzazione nella cache per l'utilizzo offline
  3. Posizionare l'immagine del supporto da visualizzare durante il caricamento
  4. Funziona bene con UITableView

Esempio rapido:

    [cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];

2
Ho modificato un po 'quella libreria e l'ho integrata con UIImage + Resize per aggiungere funzionalità di ridimensionamento / ritaglio. Se ne hai bisogno, dai un'occhiata a github.com/toptierlabs/ImageCacheResize
Tony,

1
Questo esempio popola a UIImageView. SDWebImageti permette anche di popolare UIImagedirettamente usando SDWebImageManager - (void) downloadWithURL:.... Vedi il loro esempio sul leggimi.
Bendytree,

10

E la versione rapida:

   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)

7

Se siete davvero , assolutamente positivamente sicuri che il NSURL è un file di URL, cioè [url isFileURL]è garantito per restituire true nel tuo caso, allora si può semplicemente utilizzare:

[UIImage imageWithContentsOfFile:url.path]

7

ottenere DLImageLoader e provare a seguire il codice

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

                          }];

Un altro esempio tipico del mondo reale dell'utilizzo di DLImageLoader, che può aiutare qualcuno ...

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

Come ho già detto sopra, un'altra grande biblioteca da considerare in questi giorni è Haneke (purtroppo non è così leggero).


1
SDWebImage è la libreria più popolare in Objective-C e KingFisher è la porta Swift.
XY

1
Vero, ma DLImageLoader è migliore! :)
Fattie

5

Prova questo codice, puoi impostare il caricamento dell'immagine con esso, quindi gli utenti sanno che la tua app sta caricando un'immagine dall'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"];
            }
        });
    });

2
Ho preferito questa soluzione poiché non richiedeva il caricamento di framework di terze parti o l'istanza di code di caricamento dei dati, ecc.
BillyRayCyrus,

4

Dai un'occhiata AsyncImageViewa qui . Qualche buon codice di esempio, e potrebbe anche essere utilizzabile "pronto all'uso" per te.


Esempio interessante, è molto simile nel concetto all'esempio LazyTableImages di Apple menzionato nella risposta precedente.
progrmr

È simile ma attenzione che AsyncImageView in realtà non funziona nelle tabelle, almeno non quando ricicli le celle della tabella (come dovresti).
n13

4

AFNetworking fornisce il caricamento asincrono delle immagini in UIImageView con supporto segnaposto. Supporta anche la rete asincrona per lavorare con le API in generale.


3

Assicurati di abilitare queste impostazioni da iOS 9:

Impostazioni di sicurezza del trasporto app in Info.plist per garantire il caricamento dell'immagine dall'URL in modo da consentire il download dell'immagine e impostarlo.

inserisci qui la descrizione dell'immagine

E scrivi questo codice:

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

2

Il modo in cui si utilizza un'estensione Swift a UIImageView(codice sorgente qui ):

Creazione di proprietà calcolate per gli associati 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()
            })
        }
    }

Inizializzatore e setter personalizzati

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

0

Il modo migliore e semplice per caricare l'immagine tramite URL è tramite questo codice:

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

Sostituisci imgUrlcon ImageURL
Sostituisci imgViewcon UIImageView.

Caricherà l'immagine in un altro thread, quindi non rallenterà il caricamento dell'app.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.