我可以从URL加载UIImage吗?


134

我有一个图像的URL(从UIImagePickerController中获得了它),但我的图像不再在内存中(该URL是从该应用程序的上次运行保存的)。我可以再次从URL重新加载UIImage吗?

我看到UIImage有一个imageWithContentsOfFile:但是我有一个URL。我可以使用NSData的dataWithContentsOfURL:读取URL吗?

编辑1


基于@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:relativeToURL :,然后initWithString:relativeToURL :,然后_CFStringIsLegalURLString,然后CFStringGetLength,然后forwarding_prep_0,然后转发,然后- [NSObject的doesNotRecognizeSelector。

任何想法为什么我的NSString(photoURL的地址为0x536fbe0)不响应长度?为什么说它不响应-[NSURL length]?是否不知道参数是NSString而不是NSURL?

编辑2


好的,代码的唯一问题是字符串到URL的转换。如果我对字符串进行硬编码,则其他所有功能都可以正常工作。所以我的NSString出了点问题,如果我无法弄清楚,我想应该作为另一个问题来解决。插入此行(我从上面的控制台日志粘贴了路径)后,它可以正常工作:

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

鉴于NSLog已处理,因此photoURL似乎已经是NSURL,而不是NSString。
2010年

@drawn:看起来像文档中的错误。它说UIImagePickerControllerMediaURL是一个NSString,但实际上是一个NSURL对象。
progrmr 2010年

库DLImageLoader是不可思议的。坚如磐石,没有doco,一个命令,一切都很完美。真是个发现。
Fattie 2013年

我第二(第三?)DLImageLoader。我对此页面上的评论是否客观表示怀疑-但无论如何我都尝试过,它确实很好用。我在UITableViewCell中有一个UIImageView。我所做的只是用DLImageView替换了UIImageView,然后调用了imageFromUrl:方法来加载图像,并且一切都可以正常进行-异步加载,缓存等。再简单不过了。
itnAAnti

DLImageLoader仍然很出色,另一个不错的是Haneke,尽管它由于维护不当而受到了影响。
Fattie

Answers:


319

您可以通过这种方式(同步但紧凑)来做到这一点:

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

更好的方法是使用Apple的LazyTableImages保留交互性。


1
是否不需要将数据从PNG(或JPG)文件格式转换为UIImage数据?还是UIImage以某种方式弄清楚了这一点?
progrmr 2010年

2
猜猜我应该只是RTFM,它在UIImage类参考中说了它可以支持的文件格式以及imageWithData:说它可以是文件中的数据,听起来应该可以。
progrmr 2010年

@Daniel:没用,我编辑了问题以包括我的实际代码和异常信息。这有点奇怪。
progrmr 2010年

@Daniel:如果我使用字符串常量而不是传入的NSString,它确实可以工作。因此,最新的问题是我的NSString出了点问题,而不是NSURL / NSData / UIImage代码起作用的问题。谢谢丹尼尔!
progrmr 2010年

如果您只使用一个图像,并且正在寻找一种快速修复方法,则只需编写一些代码即可缓存单个图像。
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集成在一起,以便向其添加调整大小/裁剪功能。如果您需要检查,请访问github.com/toptierlabs/ImageCacheResize
Tony

1
本示例填充UIImageViewSDWebImage还可以让您UIImage直接使用填充SDWebImageManager - (void) downloadWithURL:...。看到他们的例子在读我。
bentytree

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)

7

如果你真的,绝对是积极肯定的NSURL是一个文件的URL,即[url isFileURL]是保证在你的情况下返回true,那么你可以简单地使用:

[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更好!:)
Fattie

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

2
我更喜欢这种解决方案,因为它并不需要加载任何第三方的框架或实例数据加载队列等
BillyRayCyrus

4

AsyncImageView此处查看提供的内容。一些好的示例代码,甚至可能对您“开箱即用”可用。


有趣的示例,它在概念上与前面的答案中提到的Apple的LazyTableImages示例非常相似。
progrmr 2010年

相似,但是要注意,AsyncImageView实际上在表中不起作用,至少在您回收表单元格(如您应有的那样)时不起作用。
n13 2012年

4

AFNetworking提供了将异步图像加载到具有占位符支持的UIImageView中的功能。通常,它还支持异步网络以使用API​​。


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

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()
    }
}

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

它将在另一个线程中加载图像,因此不会降低应用程序的加载速度。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.