Czy mogę załadować UIImage z adresu URL?


134

Mam adres URL obrazu (otrzymałem go z UIImagePickerController), ale nie mam już obrazu w pamięci (adres URL został zapisany z poprzedniego uruchomienia aplikacji). Czy mogę ponownie załadować UIImage z adresu URL?

Widzę, że UIImage ma imageWithContentsOfFile: ale mam adres URL. Czy mogę użyć dataWithContentsOfURL: NSData do odczytania adresu URL?

EDYCJA1


na podstawie odpowiedzi @ Daniela Wypróbowałem następujący kod, ale nie działa ...

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

Kiedy go uruchomiłem, konsola pokazuje:

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

Patrząc na stos wywołań, wywołuję URLWithString, który wywołuje URLWithString: relativeToURL:, a następnie initWithString: relativeToURL:, następnie _CFStringIsLegalURLString, następnie CFStringGetLength, następnie forwarding_prep_0 , a następnie forwarding , a następnie - [NSObject doesSotRognize].

Jakieś pomysły, dlaczego mój NSString (adres photoURL to 0x536fbe0) nie odpowiada długości? Dlaczego jest napisane, że nie odpowiada - [długość NSURL]? Czy nie wie, że parametr to NSString, a nie NSURL?

EDYCJA2


OK, jedynym problemem z kodem jest konwersja ciągu na adres URL. Jeśli zakoduję ciąg na stałe, wszystko inne działa dobrze. Więc coś jest nie tak z moim NSString i jeśli nie mogę tego rozgryźć, myślę, że to powinno być inne pytanie. Po wstawieniu tej linii (wkleiłem ścieżkę z dziennika konsoli powyżej), działa dobrze:

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

Wygląda na to, że photoURL jest już NSURL, a nie NSStringiem, biorąc pod uwagę, że NSLog go obsłużył.
wyciągnięty

@drawn: Wygląda na błąd w dokumentacji. Mówi, że UIImagePickerControllerMediaURL to NSString, ale w rzeczywistości jest to obiekt NSURL.
progrmr

Biblioteka DLImageLoader jest NIESAMOWITA. solidne, bez dokumentu, jedno polecenie i wszystko jest idealne. Co za znalezisko.
Fattie,

I drugi (trzeci?) DLImageLoader. Byłem sceptyczny co do tego, czy komentarze na ten temat na tej stronie były obiektywne - ale i tak próbowałem i działa bardzo dobrze. Mam UIImageView w UITableViewCell. Wszystko, co zrobiłem, to zastąpienie UIImageView DLImageView, następnie wywołałem metodę imageFromUrl: w celu załadowania obrazu i wszystko po prostu działa - ładowanie asynchroniczne, buforowanie itp. Nie może być prostsze.
itnAAnti

DLImageLoader pozostaje fantastyczny, kolejnym dobrym jest Haneke , chociaż trochę cierpi z powodu niezupełnej konserwacji.
Fattie

Odpowiedzi:


319

Możesz to zrobić w ten sposób (synchronicznie, ale kompaktowo):

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

Znacznie lepszym podejściem jest użycie LazyTableImages firmy Apple w celu zachowania interaktywności.


1
Czy dane nie muszą być konwertowane z formatu pliku PNG (lub JPG) na dane UIImage? A może UIImage jakoś to rozgryza?
progrmr

2
Chyba powinienem po prostu RTFM, mówi bezpośrednio w UIImage Class Reference, jakie formaty plików obsługuje, a imageWithData: mówi, że mogą to być dane z pliku, brzmi tak, jakby powinno działać.
progrmr

@Daniel: nie zadziałało, zredagowałem moje pytanie, aby uwzględnić mój rzeczywisty kod i informacje o wyjątku. To trochę dziwne.
progrmr

@Daniel: to działa, jeśli zamiast przekazywanego NSString używam stałej łańcuchowej. Tak więc ten ostatni problem był nie tak z moim NSStringiem, a nie z działającym kodem NSURL / NSData / UIImage. Dzięki Daniel!
progrmr

Jeśli używasz tylko jednego obrazu i szukasz szybkiej naprawy, możesz po prostu napisać fragment kodu, który buforuje pojedynczy obraz.
MrDatabase,

27

Możesz wypróbować SDWebImage , zapewnia:

  1. Ładowanie asynchroniczne
  2. Buforowanie do użytku w trybie offline
  3. Obraz zastępczy pojawi się podczas ładowania
  4. Działa dobrze z UITableView

Szybki przykład:

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

2
Zmodyfikowałem nieco tę bibliotekę i zintegrowałem ją z UIImage + Resize, aby dodać do niej możliwości Resize / Crop. Jeśli potrzebujesz tego, sprawdź to na github.com/toptierlabs/ImageCacheResize
Tony,

1
Ten przykład wypełnia plik UIImageView. SDWebImageumożliwia także UIImagebezpośrednie wypełnienie pliku za pomocą SDWebImageManager - (void) downloadWithURL:.... Zobacz ich przykład na read me.
bendytree

10

I szybka wersja:

   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

Jeśli jesteś naprawdę , absolutnie pozytywnie , czy bibliotece NSURL to adres URL pliku, czyli [url isFileURL]gwarantuje powrót prawdziwe w Twoim przypadku, to możesz po prostu użyć:

[UIImage imageWithContentsOfFile:url.path]

7

pobierz DLImageLoader i spróbuj postępować zgodnie z kodem

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

                          }];

Kolejny typowy przykład użycia DLImageLoader w prawdziwym świecie, który może komuś pomóc ...

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

Jak wspomniałem powyżej, kolejną wielką biblioteką do rozważenia w dzisiejszych czasach jest Haneke (niestety nie jest tak lekka).


1
SDWebImage to najpopularniejsza biblioteka w Objective-C, a KingFisher to port Swift.
XY

1
To prawda, ale DLImageLoader jest lepszy! :)
Fattie

5

Wypróbuj ten kod, możesz ustawić za jego pomocą ładowanie obrazu, aby użytkownicy wiedzieli, że Twoja aplikacja ładuje obraz z adresu 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"];
            }
        });
    });


4

Sprawdź AsyncImageViewpodane tutaj . Dobry przykładowy kod, który może być nawet użyteczny dla Ciebie „po wyjęciu z pudełka”.


Ciekawy przykład, jest bardzo podobny w koncepcji do przykładu LazyTableImages firmy Apple wspomnianego we wcześniejszej odpowiedzi.
progrmr

Jest podobnie, ale uważaj, że AsyncImageView naprawdę nie działa w tabelach, a przynajmniej nie podczas odtwarzania komórek tabeli (tak jak powinieneś).
n13,


3

Upewnij się, że włącz te ustawienia w iOS 9:

Ustawienia zabezpieczeń transportu aplikacji w Info.plist, aby zapewnić ładowanie obrazu z adresu URL, aby umożliwić pobranie obrazu i ustawienie go.

wprowadź opis obrazu tutaj

I napisz ten kod:

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

2

Sposób korzystania z rozszerzenia Swift do UIImageView(kod źródłowy tutaj ):

Tworzenie obliczonej właściwości dla skojarzonych 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()
            })
        }
    }

Niestandardowy inicjator i ustawiający

    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

Najlepszym i najłatwiejszym sposobem załadowania obrazu przez adres URL jest ten kod:

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

Zamień imgUrlna swój ImageURL
Zastąp imgViewswoim UIImageView.

Załaduje obraz w innym wątku, więc nie spowolni ładowania aplikacji.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.