Могу ли я загрузить UIImage из URL?

134

У меня есть URL-адрес для изображения (полученный из UIImagePickerController), но у меня больше нет изображения в памяти (URL-адрес был сохранен из предыдущего запуска приложения). Могу ли я снова загрузить UIImage из URL?

Я вижу, что в UIImage есть imageWithContentsOfFile: но у меня есть URL. Могу ли я использовать NSData dataWithContentsOfURL: для чтения URL?

EDIT1


основываясь на ответе @ Daniel, я попробовал следующий код, но он не работает ...

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

Когда я запустил его, консоль показывает:

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

Глядя на стек вызовов, я вызываю URLWithString, который вызывает URLWithString :lativeToURL :, затем initWithString :lativeToURL :, затем _CFStringIsLegalURLString, затем CFStringGetLength, затем forwarding_prep_0 , затем переадресация , затем - [NSObject doesNotRecorSignS.]

Любые идеи, почему мой NSString (адрес photoURL 0x536fbe0) не отвечает на длину? Почему говорится, что он не отвечает - [длина NSURL]? Разве он не знает, что param - это NSString, а не NSURL?

EDIT2


ОК, единственная проблема с кодом - преобразование строки в URL. Если я жестко закодирую строку, все остальное работает нормально. Так что что-то не так с моей строкой NSString, и если я не могу понять это, я думаю, что это должно быть другим вопросом. С этой вставленной строкой (я вставил путь из журнала консоли выше), она работает нормально:

photoURL = @"file://localhost/Users/gary/Library/Application%20Support/iPhone%20Simulator/3.2/Media/DCIM/100APPLE/IMG_0004.JPG";
progrmr
источник
Кажется, что photoURL уже NSURL, а не NSString, учитывая, что NSLog обработал его.
обращается к
@drawn: похоже на ошибку в документации. Он говорит, что UIImagePickerControllerMediaURL является NSString, но на самом деле это объект NSURL.
progrmr
Библиотека DLImageLoader НЕВЕРОЯТНА. рок твердый, без доко, одна команда и все идеально. Какая находка
Толстяк
Я второй (третий?) DLImageLoader. Я скептически относился к тому, были ли комментарии по этому поводу на этой странице объективными, но я все равно попробовал, и это работает очень хорошо. У меня есть UIImageView в UITableViewCell. Все, что я сделал, это заменил UIImageView на DLImageView, затем вызвал imageFromUrl: метод для загрузки изображения, и все это просто работает - асинхронная загрузка, кэширование и т. Д. Не может быть проще.
itnAAnti
DLImageLoader остается фантастическим, еще один хороший - это Haneke , хотя он немного страдает от того, что не совсем поддерживается.
Толстяк

Ответы:

319

Вы можете сделать это так (синхронно, но компактно):

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

Гораздо лучшим подходом является использование Apple LazyTableImages для сохранения интерактивности.

Даниэль Блезек
источник
1
Не нужно ли преобразовывать данные из формата файла PNG (или JPG) в данные UIImage? Или UIImage это как-то выяснит?
прогрмр
2
Полагаю, мне просто RTFM, прямо в UIImage Class Reference написано, какие форматы файлов он может поддерживать, и imageWithData: говорит, что это могут быть данные из файла, похоже, что он должен работать.
прогрмр
@Daniel: не работал, я отредактировал свой вопрос, включив в него свой реальный код и информацию об исключении. Это немного странно.
progrmr
@Daniel: это работает, если я использую строковую константу вместо NSString, которую я передавал. Так что эта последняя проблема была чем-то не так с моим NSString, а не проблемой с кодом NSURL / NSData / UIImage, который работает. Спасибо Даниэль!
прогрмр
Если вы используете только одно изображение и ищете быстрое решение, вы можете просто написать немного кода, который кэширует одно изображение.
MrDatabase
27

Вы можете попробовать SDWebImage , он обеспечивает:

  1. Асинхронная загрузка
  2. Кеширование для автономного использования
  3. Поместите изображение держателя для отображения во время загрузки
  4. Хорошо работает с UITableView

Быстрый пример:

    [cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
Мухаммед Хасан Наср
источник
2
Я немного изменил эту библиотеку и интегрировал ее с UIImage + Resize, чтобы добавить в нее возможности Resize / Crop. Если вам нужно это проверить на github.com/toptierlabs/ImageCacheResize
Тони
1
Этот пример заполняет UIImageView. SDWebImageтакже позволяет заполнять UIImageнапрямую SDWebImageManager - (void) downloadWithURL:.... Смотрите их пример на прочитанном мной.
bendytree
10

И быстрая версия:

   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
источник
7

Если вы на самом деле , абсолютно положительно уверен , что NSURL является файл URL, то есть [url isFileURL]гарантированно возвращает истину в вашем случае, то вы можете просто использовать:

[UIImage imageWithContentsOfFile:url.path]
Дирадж Гупта
источник
7

получите DLImageLoader и попробуйте следующий код

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

                          }];

Другой типичный пример использования DLImageLoader, который может кому-то помочь ...

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

Как я упоминал выше, еще одна замечательная библиотека, которую стоит рассмотреть в наши дни - это Haneke (к сожалению, она не такая легкая).

Муруганандхам К
источник
1
SDWebImage - самая популярная библиотека в Objective-C, а KingFisher - это порт Swift.
XY
1
Правда, но DLImageLoader лучше! :)
Толстяк
5

Попробуйте этот код, вы можете установить загрузку изображения с ним, чтобы пользователи знали, что ваше приложение загружает изображение из 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
источник
2
Я предпочел это решение, так как оно не требовало загрузки каких-либо сторонних фреймворков или создания очередей загрузки данных и т. Д.
BillyRayCyrus
4

Проверьте AsyncImageViewпредоставленный здесь . Хороший пример кода, и он может быть даже полезен прямо из коробки.

Marcc
источник
Интересный пример, он очень похож по концепции на пример Apple LazyTableImages, упомянутый в предыдущем ответе.
progrmr
Это похоже, но имейте в виду, что AsyncImageView действительно не работает в таблицах, по крайней мере, когда вы перезапускаете ячейки таблицы (как вы должны).
n13
4

AFNetworking обеспечивает асинхронную загрузку изображений в UIImageView с поддержкой заполнителей. Он также поддерживает асинхронную сеть для работы с API в целом.

pauliephonic
источник
3

Обязательно включите эти настройки из iOS 9:

Установите параметры безопасности транспорта в Info.plist, чтобы обеспечить загрузку изображения с URL-адреса, что позволит загрузить изображение и установить его.

введите описание изображения здесь

И напишите этот код:

NSURL *url = [[NSURL alloc]initWithString:@"http://feelgrafix.com/data/images/images-1.jpg"];
NSData *data =[NSData dataWithContentsOfURL:url];
quickViewImage.image = [UIImage imageWithData:data];
Nagarjun
источник
2

Способ использования расширения Swift для UIImageView(исходный код здесь ):

Создание вычисляемого свойства для связанного 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()
            })
        }
    }

Пользовательский инициализатор и сеттер

    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
источник
0

Лучший и простой способ загрузить изображение через URL - это код:

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

Замените imgUrlсвоим ImageURL
Замените imgViewсвоим UIImageView.

Он загрузит изображение в другой поток, поэтому он не замедлит загрузку вашего приложения.

jalmatari
источник