iPhone: How to get a UIImage from a url?
How 开发者_开发知识库do you download an image and turn it into a UIImage?
NSURL *url = [NSURL URLWithString:@"http://example.com/image.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];
However, this isn't asynchronous.
You should keep in mind that loading the image data with the sample code you've provided in your own answer will block the main thread until the download has completed. This is a useability no-no. The users of your app will think your app is unresponsive. If you want to download an image, prefer NSURLConnection to download it asynchronously in its own thread.
Read the Apple documentation about async downloads with NSURLConnection.
When your download completes, you can then instantiate your UIImage from the data object:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (requestData)
{
self.image = [[[UIImage alloc] initWithData:requestData] autorelease];
}
}
Where requestData
and image
are instance variables of your containing class, and image
is a retained property. Be sure to release image
in the dealloc
routine of the class, e.g. using self.image=nil;
.
It is true that Asynchronous loading is a must, but you can also achieve that with a background call if you just need a simple solution.
[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?)
...
}
}
You can load an image in a UIImageView
from a URL without blocking the UI thread simply using the dispatch_async
:
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];
});
});
The first dispatch_async
is used to load the image from the URL in background (without blocking the UI). The second dispatch_async
is used to actually inject the image just loaded in the UIImageView
. Please, note that the second dispatch_async
is designed to work on the main thread (the UI thread) that is, indeed, the thread used to update the UI.
There is a really good example here using blocks: http://ios-blog.co.uk/iphone-development-tutorials/uiimage-from-url-%E2%80%93-simplified-using-blocks/
Based on @philfreo's answer I created a NSURL Extension in swift using BrightFutures (for the asynchronous callback:
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
}
}
This then lets me do:
import BrightFutures
let someURL = ...;
someURL.downloadImage().onSuccess{ image in
// Do something with the UIImage
}
Update
A simple synchronous extension could look like this:
extension NSURL{
func downloadImage() -> UIImage?{
if let data = NSData(contentsOfURL: self){
return UIImage(data: data){
}
return nil
}
}
This is what @philfreo's answer looks like in swift:
let urlString = "http://lorempixel.com/100/100/cats/"
let url = NSURL(string: urlString)!
let data = NSData(contentsOfURL: url)
let image = UIImage(data: data!)
This works in a playground:
精彩评论