iPhone: 如何从URL获取UIImage?

21

您如何下载一张图片并将其转换为UIImage?


我在这里提出/回答自己的问题,因为对于这个问题的谷歌搜索结果已经不再适用于最新的SDK。 - philfreo
这个库将为您完成所有与Web相关的工作,以异步方式从URL创建图像:https://github.com/rs/SDWebImage - vir us
7个回答

42
NSURL *url = [NSURL URLWithString:@"http://example.com/image.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];

然而,这并不是异步的。


15
请注意,使用您在自己的答案中提供的示例代码加载图像数据会阻塞主线程,直到下载完成。这是一个不可接受的用法。您的应用程序用户将认为您的应用程序无响应。如果您想要下载图像,请优先选择 NSURLConnection,在其自己的线程中异步下载它。 阅读有关使用 NSURLConnection 进行异步下载的苹果文档。 当下载完成时,您可以从数据对象实例化 UIImage:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    if (requestData)
    {
        self.image = [[[UIImage alloc] initWithData:requestData] autorelease];
    }
}

requestDataimage是您所包含的类的实例变量,且image是一个保留属性。请确保在类的dealloc过程中释放image,例如使用self.image=nil;


1
很好的观点。我也刚看了这个链接:http://www.markj.net/iphone-asynchronous-table-image/ - philfreo
2
这是绝对必须的。以下是几个使用块处理异步UIImage加载和缓存的类。http://t.co/ovOn86KG - Andrew Zimmer
Andrew - 使用您的基于块的方法,生成的UIImage是否在后台线程上返回?如果是这样,我认为在将其分配给UIImageView时,需要使用performSelectorOnMainThread在主线程上显式执行 - 是吗? - Rob Reuss
看一下我的回答中提到的几个库。我在一个项目中一直在使用它,效果非常好。 - Tony

5
您可以使用dispatch_async简单地从URL加载UIImageView中的图像,而不会阻塞UI线程:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSURL *url = [NSURL URLWithString:myURL];
            NSData *data = [NSData dataWithContentsOfURL:url];
            UIImage* image = [[UIImage alloc]initWithData:data];

            dispatch_async(dispatch_get_main_queue(), ^{
                [myImageView setImage:image];
            });
        });

第一个dispatch_async用于在后台加载图像(而不会阻塞UI)。第二个dispatch_async用于将刚刚加载的图像注入到UIImageView中。请注意,第二个dispatch_async被设计为在主线程(即更新UI的线程)上运行。


5

虽然异步加载确实必要,但如果只需要简单的解决方案,您也可以通过后台调用来实现。

[self performSelectorInBackground:@selector(loadImage) withObject:nil];

- (void)loadImage
{
   NSURL * url = [NSURL URLWithString:@"http://.../....jpg"];
   NSData * data = [NSData dataWithContentsOfURL:url];
   UIImage * image = [UIImage imageWithData:data];
   if (image)
   {
       // Success use the image
       ...
   }
   else
   {
       // Failed (load an error image?)
       ...
   }
}   

2

1

根据 @philfreo 的回答,我使用 BrightFutures 在 Swift 中创建了一个 NSURL 扩展来进行异步回调:

extension NSURL{
    func downloadImage() -> Future<UIImage, NSError>{

        let promise = Promise<UIImage, NSError>()

        Queue.global.async{
            if let data = NSData(contentsOfURL: self){
                if let image = UIImage(data: data){
                    promise.success(image)
                    return
                }
            }
            promise.failure(NSError())
        }

        return promise.future
    }
}

这样我就可以做到:
import BrightFutures

let someURL = ...;
someURL.downloadImage().onSuccess{ image in
  // Do something with the UIImage
}

更新

一个简单的同步扩展可以像这样:

extension NSURL{
    func downloadImage() -> UIImage?{
        if let data = NSData(contentsOfURL: self){
            return UIImage(data: data){
        }
    return nil
    }
}

0

这是@philfreo在Swift中的答案:

let urlString = "http://lorempixel.com/100/100/cats/"
let url = NSURL(string: urlString)!
let data = NSData(contentsOfURL: url)
let image = UIImage(data: data!)

这在游乐场里可以运行:

image


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接