Kann ich ein UIImage von einer URL laden?

134

Ich habe eine URL für ein Bild (habe sie von UIImagePickerController erhalten), aber ich habe das Bild nicht mehr im Speicher (die URL wurde aus einer früheren Ausführung der App gespeichert). Kann ich das UIImage erneut von der URL laden?

Ich sehe, dass UIImage ein imageWithContentsOfFile hat: aber ich habe eine URL. Kann ich die DataWithContentsOfURL: von NSData verwenden, um die URL zu lesen?

EDIT1


basierend auf @ Daniels Antwort habe ich den folgenden Code ausprobiert, aber er funktioniert nicht ...

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

Wenn ich es ausgeführt habe, zeigt die Konsole:

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

Wenn ich mir den Aufrufstapel anschaue, rufe ich URLWithString auf, das URLWithString: relativeToURL:, dann initWithString: relativeToURL:, dann _CFStringIsLegalURLString, dann CFStringGetLength, dann forwarding_prep_0 , dann forwarding , dann - [NSObject doesNelRecize.

Irgendwelche Ideen, warum mein NSString (die Adresse von photoURL ist 0x536fbe0) nicht auf die Länge reagiert? Warum sagt es, dass es nicht auf - [NSURL-Länge] reagiert? Weiß es nicht, dass param ein NSString ist, kein NSURL?

EDIT2


OK, das einzige Problem mit dem Code ist die Konvertierung von Zeichenfolge in URL. Wenn ich die Zeichenfolge fest codiere, funktioniert alles andere einwandfrei. Mit meinem NSString stimmt also etwas nicht, und wenn ich es nicht herausfinden kann, sollte das eine andere Frage sein. Wenn diese Zeile eingefügt ist (ich habe den Pfad aus dem obigen Konsolenprotokoll eingefügt), funktioniert dies einwandfrei:

photoURL = @"file://localhost/Users/gary/Library/Application%20Support/iPhone%20Simulator/3.2/Media/DCIM/100APPLE/IMG_0004.JPG";
Progrmr
quelle
Es scheint, dass photoURL bereits eine NSURL ist, keine NSString, da NSLog damit umgegangen ist.
gezogen
@drawn: Sieht aus wie ein Fehler in den Dokumenten. Es heißt, dass UIImagePickerControllerMediaURL ein NSString ist, aber tatsächlich ein NSURL-Objekt.
Programm
Die Bibliothek DLImageLoader ist UNGLAUBLICH. absolut solide, kein Dokument, ein Befehl und alles ist perfekt. Was für ein Fund.
Fattie
Ich zweiter (dritter?) DLImageLoader. Ich war skeptisch, ob die Kommentare auf dieser Seite objektiv waren - aber ich habe es trotzdem versucht und es funktioniert sehr gut. Ich habe eine UIImageView in einer UITableViewCell. Ich habe lediglich die UIImageView durch eine DLImageView ersetzt und dann die imageFromUrl: -Methode zum Laden des Bildes aufgerufen. Alles funktioniert einfach - asynchrones Laden, Zwischenspeichern usw. Könnte nicht einfacher sein.
itnAAnti
DLImageLoader bleibt fantastisch, ein weiteres gutes ist Haneke , obwohl es ein wenig darunter leidet, nicht ganz gewartet zu werden.
Fattie

Antworten:

319

Sie können dies folgendermaßen tun (synchron, aber kompakt):

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

Ein viel besserer Ansatz ist die Verwendung von LazyTableImages von Apple, um die Interaktivität zu erhalten.

Daniel Blezek
quelle
1
Müssen die Daten nicht vom PNG- (oder JPG-) Dateiformat in UIImage-Daten konvertiert werden? Oder findet UIImage das irgendwie heraus?
Programm
2
Ich denke, ich sollte nur RTFM, es steht direkt in der UIImage-Klassenreferenz, welche Dateiformate es unterstützen kann, und imageWithData: sagt, es können Daten aus einer Datei sein, klingt so, als ob es funktionieren sollte.
Programm
@ Daniel: hat nicht funktioniert, ich habe meine Frage so bearbeitet, dass sie meinen tatsächlichen Code und die Ausnahmeinformationen enthält. Es ist ein bisschen bizarr.
Programm
@ Daniel: Es funktioniert, wenn ich anstelle des übergebenen NSString eine Zeichenfolgenkonstante verwende. Dieses neueste Problem stimmte also nicht mit meinem NSString überein, nicht mit dem funktionierenden NSURL / NSData / UIImage-Code. Danke Daniel!
Programm
Wenn Sie nur ein Bild verwenden und nach einer schnellen Lösung suchen, können Sie einfach ein bisschen Code schreiben, der das einzelne Bild zwischenspeichert.
MrDatabase
27

Sie können SDWebImage ausprobieren , es bietet:

  1. Asynchrones Laden
  2. Caching für die Offline-Verwendung
  3. Platzieren Sie das Halterbild so, dass es beim Laden angezeigt wird
  4. Funktioniert gut mit UITableView

Kurzes Beispiel:

    [cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
Muhammad Hassan Nasr
quelle
2
Ich habe diese Bibliothek ein wenig modifiziert und in UIImage + Resize integriert, um ihr die Funktionen Resize / Crop hinzuzufügen. Wenn Sie das brauchen, lesen Sie es unter github.com/toptierlabs/ImageCacheResize
Tony
1
In diesem Beispiel wird a ausgefüllt UIImageView. SDWebImageSie können auch eine UIImagedirekt mit füllen SDWebImageManager - (void) downloadWithURL:.... Siehe ihr Beispiel auf der Read me.
Bendytree
10

Und die schnelle Version:

   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)
user3763002
quelle
7

Wenn Sie wirklich , absolut positiv sicher , dass die NSURL eine Datei - URL, also [url isFileURL]ist garantiert return true in Ihrem Fall, dann können Sie einfach verwenden:

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

Holen Sie sich DLImageLoader und versuchen Sie, Code zu folgen

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

                          }];

Ein weiteres typisches Beispiel aus der Praxis für die Verwendung von DLImageLoader, das jemandem helfen kann ...

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

Wie ich oben erwähne, ist Haneke eine weitere großartige Bibliothek, die man heutzutage in Betracht ziehen sollte (leider ist sie nicht so leicht).

Muruganandham K.
quelle
1
SDWebImage ist die beliebteste Bibliothek in Objective-C und KingFisher ist der Swift-Port.
XY
1
Stimmt, aber DLImageLoader ist besser! :)
Fattie
5

Versuchen Sie diesen Code, Sie können das Laden von Bildern damit festlegen, damit die Benutzer wissen, dass Ihre App ein Bild von der URL lädt:

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
quelle
2
Ich habe diese Lösung vorgezogen, da keine Frameworks von
Drittanbietern geladen
4

Schauen Sie sich das hier zur AsyncImageViewVerfügung gestellte an . Ein guter Beispielcode, der möglicherweise sogar "out of the box" für Sie verwendet werden kann.

marcc
quelle
Interessantes Beispiel, das Konzept ist dem in der vorherigen Antwort erwähnten LazyTableImages-Beispiel von Apple sehr ähnlich.
Programm
Es ist ähnlich, aber beachten Sie, dass AsyncImageView in Tabellen wirklich nicht funktioniert, zumindest nicht, wenn Sie Tabellenzellen recyceln (wie Sie sollten).
n13
4

AFNetworking ermöglicht das Laden von asynchronen Bildern in eine UIImageView mit Platzhalterunterstützung. Es unterstützt auch asynchrone Netzwerke für die Arbeit mit APIs im Allgemeinen.

pauliephonic
quelle
3

Stellen Sie sicher, dass diese Einstellungen unter iOS 9 aktiviert sind:

App Transport-Sicherheitseinstellungen in Info.plist , um sicherzustellen , dass das Bild von der URL geladen wird , damit das Bild heruntergeladen und festgelegt werden kann.

Geben Sie hier die Bildbeschreibung ein

Und schreibe diesen Code:

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

Der Weg mit einer Swift- Erweiterung zu UIImageView(Quellcode hier ):

Berechnete Eigenschaft für Associated erstellen 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()
            })
        }
    }

Benutzerdefinierter Initializer und 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
quelle
0

Der beste und einfachste Weg, um ein Bild über die URL zu laden, ist dieser Code:

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

Ersetzen imgUrldurch Ihre ImageURL
Ersetzen imgViewdurch Ihre UIImageView.

Das Image wird in einen anderen Thread geladen, sodass das Laden der App nicht verlangsamt wird.

Jalmatari
quelle