Asynchronous images on iOS

The iOS SDK provides many ways to manipulate images. The simplest way is loading an Image into an UIImageView. The issue of this way is that loading the image in that way is a synchronous operations:

UIImageView *imageView = [[UIImageView alloc] initWithFrame: CGRectMake(100.0, 100.0, 57.0, 57.0)];

NSData* data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"image.jpg"]];

UIImage* image = [[UIImage alloc] initWithData:data];

[imageView setImage:image];

[image release];

[data release];

When you are loading many images, synchronous operations are not your best friend because it does not have a good performance. In this case you will prefer to load the images asynchronously. To do that, you can solve the situation using threads. But I want a reusable solution based on classes, so I decide to extend the UIImage to do that.

My code is based on the code of iOS Dev Tips, but instead of use an UIImageView I decide to use an UIImage. The strategy is download the image as a NSData in background and use a delegate to notify your classe. Follow the AsynchronousUIImage.h :

#import

@class AsynchronousUIImage;

@protocol AsynchronousUIImageDelegate

@optional

-(void) imageDidLoad:(AsynchronousUIImage *)anImage;

@end

@interface AsynchronousUIImage : UIImage{

NSURLConnection *connection;

NSMutableData *data;

}

@property (nonatomic, assign) id  delegate;

@property (nonatomic)  int tag;

- (void)loadImageFromURL:(NSString *)anUrl;
@end

The protocol has one optional method called imageDidLoad:(AsynchronousUIImage *)anImage so your code can be notified that the image has loaded. The interface has two properties one for the delegate and the other one is a tag to identification when the delegate is called.

So, let’s go to the implementation:

@implementation AsynchronousUIImage

@synthesize delegate;

@synthesize tag;

- (void)loadImageFromURL:(NSString *)anUrl {

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:anUrl]

cachePolicy:NSURLRequestReturnCacheDataElseLoad

timeoutInterval:30.0];

connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

}

- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData {

if (data == nil)

data = [[NSMutableData alloc] initWithCapacity:2048];

[data appendData:incrementalData];

}

- (void)connectionDidFinishLoading:(NSURLConnection *)theConnection

{

[self initWithData:data];

[data release], data = nil;

[connection release], connection = nil;

[self.delegate imageDidLoad:self];

}

-(void)dealloc{

[super dealloc];

connection = nil;

data = nil;

}

In the loadImageFromURL method we use NSURLConnection to get the data from the web then in the didReceiveData method we get the pieces of data and finally in the connectionDidFinishLoading method we set the data to the UIImage object, do the memory management and call the delegate method.

So, you can use AsynchronousUIImage class that way:

AsynchronousUIImage *image = [[AsynchronousUIImage alloc] init];

[image loadImageFromURL: @"http://yourimage" ];

image.tag = 1;

image.delegate = self;

[image release];

And then implement the imageDidLoad delegate method that way:

-(void) imageDidLoad:(AsynchronousUIImage *)anImage{

 if (anImage.tag == 1) {

 myImageView.image = anImage;

 }

}

You can find a complete example in: https://github.com/gazolla/AsyncImageTest

See you at WWDC 2012

20110610-031038.jpg

The business card for WWDC

20110606-080435.jpg

And the badge…

20110605-112416.jpg

Done !!

20110605-101935.jpg

Getting the badge II

Getting the badge

20110605-093754.jpg

Everything ready !

WWDC will start on monday !

20110604-055646.jpg

Welcome to Gazapps

This is our site about Mac and iOs development.




Premium Wordpress Plugin