Puis-je charger une UIImage à partir d'une URL?


134

J'ai une URL pour une image (obtenue à partir de UIImagePickerController) mais je n'ai plus l'image en mémoire (l'URL a été enregistrée à partir d'une précédente exécution de l'application). Puis-je recharger UIImage à partir de l'URL?

Je vois que UIImage a un imageWithContentsOfFile: mais j'ai une URL. Puis-je utiliser dataWithContentsOfURL: de NSData pour lire l'URL?

EDIT1


basé sur la réponse de @ Daniel, j'ai essayé le code suivant mais cela ne fonctionne pas ...

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

Quand je l'ai lancé, la console affiche:

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

En regardant la pile d'appels, j'appelle URLWithString, qui appelle URLWithString: relativeToURL :, puis initWithString: relativeToURL :, puis _CFStringIsLegalURLString, puis CFStringGetLength, puis forwarding_prep_0 , puis transfert , puis - [NSObject doesNotRecognize].

Des idées pourquoi ma NSString (l'adresse de photoURL est 0x536fbe0) ne répond pas à la longueur? Pourquoi dit-il qu'il ne répond pas à - [longueur NSURL]? Ne sait-il pas que param est une NSString, pas une NSURL?

EDIT2


OK, le seul problème avec le code est la conversion de chaîne en URL. Si je code en dur la chaîne, tout le reste fonctionne bien. Donc, quelque chose ne va pas avec ma NSString et si je ne peux pas le comprendre, je suppose que cela devrait être une question différente. Avec cette ligne insérée (j'ai collé le chemin du journal de la console ci-dessus), cela fonctionne bien:

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

Il semble que photoURL est déjà une NSURL, pas une NSString, étant donné que NSLog l'a gérée.
dessiné

@drawn: ressemble à une erreur dans la documentation. Il dit que UIImagePickerControllerMediaURL est une NSString mais c'est en fait un objet NSURL.
programme

La bibliothèque DLImageLoader est INCROYABLE. solide comme le roc, pas de doco, une seule commande et tout est parfait. Quelle trouvaille.
Fattie

Je deuxième (troisième?) DLImageLoader. J'étais sceptique quant à savoir si les commentaires à ce sujet sur cette page étaient objectifs - mais je l'ai quand même essayé et cela fonctionne très bien. J'ai un UIImageView dans un UITableViewCell. Tout ce que j'ai fait a été de remplacer UIImageView par un DLImageView, puis j'ai appelé la méthode imageFromUrl: pour charger l'image, et tout fonctionne simplement - chargement asynchrone, mise en cache, etc. Cela ne pourrait pas être plus facile.
itnAAnti

DLImageLoader reste fantastique, un autre bon est Haneke , bien qu'il souffre un peu de ne pas être tout à fait entretenu.
Fattie

Réponses:


319

Vous pouvez le faire de cette façon (de manière synchrone, mais compacte):

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

Une bien meilleure approche consiste à utiliser LazyTableImages d'Apple pour préserver l'interactivité.


1
Les données n'ont-elles pas besoin d'être converties du format de fichier PNG (ou JPG) en données UIImage? Ou est-ce que UIImage comprend cela d'une manière ou d'une autre?
programme

2
Je suppose que je devrais juste RTFM, il dit directement dans UIImage Class Reference quels formats de fichiers il peut prendre en charge et imageWithData: dit que cela peut être des données d'un fichier, cela semble fonctionner.
programme

@Daniel: n'a pas fonctionné, j'ai édité ma question pour inclure mon code réel et les informations d'exception. C'est un peu bizarre.
progrmr

@Daniel: cela fonctionne si j'utilise une constante de chaîne au lieu de la NSString que je transmettais. Donc, ce dernier problème était quelque chose de mal avec mon NSString, pas un problème avec le code NSURL / NSData / UIImage qui fonctionne. Merci Daniel!
progrmr

Si vous n'utilisez qu'une seule image et que vous recherchez une solution rapide, vous pouvez simplement écrire un peu de code qui met en cache l'image unique.
MrDatabase

27

Vous pouvez essayer SDWebImage , il fournit:

  1. Chargement asynchrone
  2. Mise en cache pour une utilisation hors ligne
  3. Faire apparaître l'image de réserve lors du chargement
  4. Fonctionne bien avec UITableView

Exemple rapide:

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

2
J'ai un peu modifié cette bibliothèque et l'ai intégrée à UIImage + Resize afin d'y ajouter des capacités de redimensionnement / recadrage. Si vous en avez besoin, consultez-le sur github.com/toptierlabs/ImageCacheResize
Tony

1
Cet exemple remplit un fichier UIImageView. SDWebImagevous permet également de remplir UIImagedirectement un fichier SDWebImageManager - (void) downloadWithURL:.... Voir leur exemple sur le read me.
bendytree

10

Et la version rapide:

   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

Si vous êtes vraiment , absolument positivement sûr que le NSURL est une URL de fichier, à savoir [url isFileURL]est garanti pour retourner vrai dans votre cas, vous pouvez simplement utiliser:

[UIImage imageWithContentsOfFile:url.path]

7

obtenez DLImageLoader et essayez le code suivant

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

                          }];

Un autre exemple typique du monde réel d'utilisation de DLImageLoader, qui peut aider quelqu'un ...

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

Comme je l'ai mentionné ci-dessus, une autre grande bibliothèque à considérer ces jours-ci est Haneke (malheureusement, elle n'est pas aussi légère).


1
SDWebImage est la bibliothèque la plus populaire d'Objective-C et KingFisher est le port Swift.
XY

1
C'est vrai, mais DLImageLoader est meilleur! :)
Fattie

5

Essayez ce code, vous pouvez définir le chargement de l'image avec celui-ci, afin que les utilisateurs sachent que votre application charge une image à partir de l'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
J'ai préféré cette solution car elle ne nécessitait pas de chargement de frameworks tiers ni d'instanciation de files d'attente de chargement de données, etc.
BillyRayCyrus

4

Découvrez le AsyncImageViewfourni ici . Un bon exemple de code, et pourrait même être utilisable dès la sortie de la boîte pour vous.


Exemple intéressant, son concept est très similaire à l'exemple LazyTableImages d'Apple mentionné dans la réponse précédente.
programme

C'est similaire, mais sachez qu'AsyncImageView ne fonctionne vraiment pas dans les tableaux, du moins pas lorsque vous recyclez les cellules d'un tableau (comme vous devriez).
n13

4

AFNetworking fournit le chargement d'image asynchrone dans une UIImageView avec prise en charge des espaces réservés. Il prend également en charge la mise en réseau asynchrone pour travailler avec les API en général.


3

Assurez-vous d'activer ces paramètres à partir d'iOS 9:

Paramètres de sécurité du transport d'application dans Info.plist pour assurer le chargement de l'image à partir de l'URL afin qu'elle autorise le téléchargement de l'image et la définisse.

entrez la description de l'image ici

Et écrivez ce code:

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

2

La façon d'utiliser une extension Swift pour UIImageView(code source ici ):

Création d'une propriété calculée pour Associated 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()
            })
        }
    }

Initialiseur et poseur personnalisés

    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

Le moyen le meilleur et le plus simple de charger une image via une URL consiste à utiliser ce 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];
    });
});

Remplacez imgUrlpar votre ImageURL
Remplacez imgViewpar votre UIImageView.

Il chargera l'image dans un autre fil, donc il ne ralentira pas le chargement de votre application.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.