Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading an image into UIImage asynchronously

I'm developing an iOS 4 application with iOS 5.0 SDK and XCode 4.2.

I have to show some post blogs into a UITableView. When I have retreived all web service data, I use this method to create an UITableViewCell:

- (BlogTableViewCell *)tableView:(UITableView *)tableView          cellForRowAtIndexPath:(NSIndexPath *)indexPath {     static NSString* cellIdentifier = @"BlogCell";      BlogTableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];      if (cell == nil)     {         NSArray* topLevelObjects =  [[NSBundle mainBundle] loadNibNamed:@"BlogTableViewCell" owner:nil options:nil];          for(id currentObject in topLevelObjects)         {             if ([currentObject isKindOfClass:[BlogTableViewCell class]])             {                 cell = (BlogTableViewCell *)currentObject;                 break;             }         }     }      BlogEntry* entry = [blogEntries objectAtIndex:indexPath.row];      cell.title.text = entry.title;     cell.text.text = entry.text;     cell.photo.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:entry.photo]]];      return cell; } 

But this line:

cell.photo.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:entry.photo]]]; 

it is so slow (entry.photo has a http url).

Is there any way to load that image asynchronously? I think it is difficult because tableView:cellForRowAtIndexPath is called very often.

like image 704
VansFannel Avatar asked Mar 20 '12 11:03

VansFannel


People also ask

Can we store image in Userdefaults?

It is, but it isn't possible to store an image as is in the user's defaults database. The defaults system only supports strings, numbers, Date objects, and Data objects. This means that you need to convert the image to a Data object before you can store it in the user's defaults database.

What is the difference between UIImage and UIImageView?

UIImage contains the data for an image. UIImageView is a custom view meant to display the UIImage .


2 Answers

I wrote a custom class to do just this, using blocks and GCD:

WebImageOperations.h

#import <Foundation/Foundation.h>  @interface WebImageOperations : NSObject { }  // This takes in a string and imagedata object and returns imagedata processed on a background thread + (void)processImageDataWithURLString:(NSString *)urlString andBlock:(void (^)(NSData *imageData))processImage; @end 

WebImageOperations.m

#import "WebImageOperations.h" #import <QuartzCore/QuartzCore.h>  @implementation WebImageOperations   + (void)processImageDataWithURLString:(NSString *)urlString andBlock:(void (^)(NSData *imageData))processImage {     NSURL *url = [NSURL URLWithString:urlString];      dispatch_queue_t callerQueue = dispatch_get_current_queue();     dispatch_queue_t downloadQueue = dispatch_queue_create("com.myapp.processsmagequeue", NULL);     dispatch_async(downloadQueue, ^{         NSData * imageData = [NSData dataWithContentsOfURL:url];          dispatch_async(callerQueue, ^{             processImage(imageData);         });     });     dispatch_release(downloadQueue); }  @end 

And in your ViewController

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {      // Pass along the URL to the image (or change it if you are loading there locally)     [WebImageOperations processImageDataWithURLString:entry.photo andBlock:^(NSData *imageData) {     if (self.view.window) {         UIImage *image = [UIImage imageWithData:imageData];          cell.photo.image = image;     }      }]; } 

It is very fast and will load the images without affecting the UI or scrolling speed of the TableView.

*** Note - This example assumes ARC is being used. If not, you will need to manage your own releases on objects)

like image 162
LJ Wilson Avatar answered Nov 02 '22 22:11

LJ Wilson


In iOS 6 and later dispatch_get_current_queue gives deprecation warnings.

Here is an alternative that is a synthesis of the @ElJay answer above and the article by @khanlou here.

Create a category on UIImage:

UIImage+Helpers.h

@interface UIImage (Helpers)  + (void) loadFromURL: (NSURL*) url callback:(void (^)(UIImage *image))callback;  @end 

UIImage+Helpers.m

#import "UIImage+Helpers.h"  @implementation UIImage (Helpers)  + (void) loadFromURL: (NSURL*) url callback:(void (^)(UIImage *image))callback {     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);     dispatch_async(queue, ^{         NSData * imageData = [NSData dataWithContentsOfURL:url];         dispatch_async(dispatch_get_main_queue(), ^{             UIImage *image = [UIImage imageWithData:imageData];             callback(image);         });     }); }  @end 
like image 39
bbrame Avatar answered Nov 02 '22 22:11

bbrame