Posso carregar uma UIImage de um URL?

134

Eu tenho um URL para uma imagem (peguei no UIImagePickerController), mas não tenho mais a imagem na memória (o URL foi salvo de uma execução anterior do aplicativo). Posso recarregar a UIImage do URL novamente?

Vejo que UIImage tem um imageWithContentsOfFile: mas tenho um URL. Posso usar o dataWithContentsOfURL do NSData: para ler a URL?

EDIT1


com base na resposta de @ Daniel, tentei o código a seguir, mas ele não 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];
}

Quando o executei, o 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'

Olhando para a pilha de chamadas, estou chamando URLWithString, que chama URLWithString: relativeToURL:; em seguida, initWithString: relativeToURL :, depois _CFStringIsLegalURLString, CFStringGetLength, forwarding_prep_0 , forwarding_prep_0 , encaminhamento e , em seguida, - [NSObject doesNotRecognizeSelector].

Alguma idéia de por que meu NSString (o endereço do photoURL é 0x536fbe0) não responde por muito tempo? Por que diz que não responde a - [comprimento NSURL]? Não sabe que param é um NSString, não um NSURL?

EDIT2


OK, o único problema com o código é a conversão de string para URL. Se eu codificar a string, tudo funcionará bem. Então, algo está errado com o meu NSString e, se não consigo descobrir, acho que isso deve ser uma pergunta diferente. Com esta linha inserida (colei o caminho do log do console acima), ele funciona bem:

photoURL = @"file://localhost/Users/gary/Library/Application%20Support/iPhone%20Simulator/3.2/Media/DCIM/100APPLE/IMG_0004.JPG";
progrmr
fonte
Parece que o photoURL já é um NSURL, não um NSString, dado que o NSLog o tratou.
Drawonward
@drawn: parece um erro nos documentos. Ele diz que UIImagePickerControllerMediaURL é um NSString, mas na verdade é um objeto NSURL.
progrmr
A biblioteca DLImageLoader é INCREDIBLE. rock solid, no doco, um comando e tudo é perfeito. Que descoberta.
Fattie
Eu segundo (terceiro?) DLImageLoader. Fiquei cético sobre se os comentários sobre esta página eram objetivos - mas tentei mesmo assim e funciona muito bem. Eu tenho um UIImageView dentro de um UITableViewCell. Tudo o que fiz foi substituir o UIImageView por um DLImageView, chamado de imageFromUrl: método para carregar a imagem, e tudo funciona - carregamento assíncrono, cache, etc. Não poderia ser mais fácil.
itnAAnti
O DLImageLoader permanece fantástico, outro bom é o Haneke , embora sofra um pouco por não ser bem mantido.
Fattie

Respostas:

319

Você pode fazer desta maneira (de forma síncrona, mas compacta):

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

Uma abordagem muito melhor é usar o LazyTableImages da Apple para preservar a interatividade.

Daniel Blezek
fonte
1
Os dados não precisam ser convertidos do formato de arquivo PNG (ou JPG) para os dados da UIImage? Ou a UIImage descobre isso de alguma forma?
progrmr
2
Acho que eu deveria apenas RTFM, diz na UIImage Class Reference quais formatos de arquivo ele suporta e imageWithData: diz que pode ser dados de um arquivo, parece que deve funcionar.
progrmr
@ Daniel: não funcionou, editei minha pergunta para incluir meu código real e as informações da exceção. É um pouco bizarro.
progrmr
@ Daniel: funciona se eu usar uma constante de string em vez do NSString que eu estava passando. Portanto, esse problema mais recente foi algo errado com o meu NSString, não com o código NSURL / NSData / UIImage que funciona. Obrigado Daniel!
Progrmr
Se você estiver usando apenas uma imagem e estiver procurando uma solução rápida, basta escrever um pouco de código que armazena em cache a imagem única.
MrDatabase 12/02
27

Você pode tentar o SDWebImage , ele fornece:

  1. Carregamento assíncrono
  2. Armazenamento em cache para uso offline
  3. Imagem do espaço reservado para aparecer durante o carregamento
  4. Funciona bem com UITableView

Exemplo rápido:

    [cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"] placeholderImage:[UIImage imageNamed:@"placeholder.png"]];
Muhammad Hassan Nasr
fonte
2
Modifiquei um pouco essa biblioteca e a integrei ao UIImage + Resize para adicionar recursos de Redimensionar / Recortar. Se você precisar disso, verifique em github.com/toptierlabs/ImageCacheResize
Tony
1
Este exemplo preenche a UIImageView. SDWebImagetambém permite que você preencha um UIImageusando diretamente SDWebImageManager - (void) downloadWithURL:.... Veja o exemplo deles no leia-me.
bendytree
10

E a versão 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)
user3763002
fonte
7

Se você está realmente , absolutamente positivamente certeza de que o NSURL é uma URL do arquivo, ou seja, [url isFileURL]é garantida para retornar verdade no seu caso, então você pode simplesmente usar:

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

obtenha o DLImageLoader e tente seguir o código

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

                          }];

Outro exemplo típico do mundo real do uso do DLImageLoader, que pode ajudar alguém ...

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 mencionei acima, outra grande biblioteca a considerar atualmente é Haneke (infelizmente não é tão leve).

Muruganandham K
fonte
1
SDWebImage é a biblioteca mais popular em Objective-C e KingFisher é a porta Swift.
XY
1
É verdade, mas o DLImageLoader é melhor! :)
Fattie
5

Experimente este código, você pode definir o carregamento de uma imagem para que os usuários saibam que seu aplicativo está carregando uma imagem do 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
fonte
2
Eu preferia esta solução uma vez que não necessitam de carregar quaisquer estruturas 3o partido ou instanciar o carregamento de dados filas, etc.
BillyRayCyrus
4

Confira o AsyncImageViewfornecido aqui . Um bom exemplo de código e pode até ser útil "pronto para uso" para você.

marcc
fonte
Exemplo interessante, é muito semelhante em conceito ao exemplo LazyTableImages da Apple mencionado na resposta anterior.
progrmr
É semelhante, mas cuidado, pois o AsyncImageView realmente não funciona em tabelas, pelo menos não quando você recicla as células da tabela (como deveria).
n13 07/02/12
4

O AFNetworking fornece carregamento de imagem assíncrona em um UIImageView com suporte a espaço reservado. Ele também suporta redes assíncronas para trabalhar com APIs em geral.

pauliephonic
fonte
3

Certifique-se de ativar essas configurações no iOS 9:

As Configurações de segurança de transporte de aplicativos no Info.plist garantem o carregamento da imagem a partir do URL para permitir o download da imagem e configurá-la.

insira a descrição da imagem aqui

E escreva 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
fonte
2

Como usar uma extensão Swift para UIImageView(código fonte aqui ):

Criando propriedade computada para associados 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 e setter personalizados

    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
fonte
0

A melhor e mais fácil maneira de carregar uma imagem via URL é por 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];
    });
});

Substitua imgUrlpelo seu ImageURL
Substitua imgViewpelo seu UIImageView.

Ele carregará a imagem em outro segmento, portanto, não diminuirá o carregamento do aplicativo.

jalmatari
fonte