iOS SDK: Lazy Image Downloading.

I’ve had a couple people ask me for the code behind the image loading that’s referenced in my updates for fast scrolling post and I’m making good on a promise to post the code for everyone else to use. It’s shown below:

ImageDownloader.h

//
//  ImageDownloader.h
//  Lobaco
//
//  Created by David Klemke on 14/10/10.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import
@class Post;

@protocol ImageDownloadDelegate;

@interface ImageDownloader : NSObject {
	Post *post;
	NSIndexPath *indexPathInTableView;
	id  delegate;

	NSMutableData *activeDownload;
	NSURLConnection *imageConnection;
	bool downloadPostImage;
}

@property (nonatomic, retain) Post *post;
@property (nonatomic, retain) NSIndexPath *indexPathInTableView;
@property (nonatomic, assign) id  delegate;
@property bool downloadPostImage;
@property (nonatomic, retain) NSMutableData *activeDownload;
@property (nonatomic, retain) NSURLConnection *imageConnection;

- (void)startDownload;
- (void)cancelDownload;

@end

@protocol ImageDownloadDelegate

-(void)imageDidLoad: (NSIndexPath *)indexPath;

@end

ImageDownloader.m

//
//  ImageDownloader.m
//  Lobaco
//
//  Created by David Klemke on 14/10/10.
//  Copyright 2010 __MyCompanyName__. All rights reserved.
//

#import "ImageDownloader.h"
#import "Post.h"

#define kImageHeight 75

@implementation ImageDownloader

@synthesize post;
@synthesize indexPathInTableView;
@synthesize delegate;
@synthesize activeDownload;
@synthesize imageConnection;
@synthesize downloadPostImage;

#pragma mark

- (void)dealloc
{
	[post release];
	[indexPathInTableView release];
	[activeDownload release];
	[imageConnection cancel];
	[imageConnection release];
	[super dealloc];
}

- (void)startDownload
{
	self.activeDownload = [NSMutableData data];
	//NSLog(@"%@",[post.data objectForKey:@"ProfileImage"]);
	NSURL *url;
	if (downloadPostImage)
	{
		url = [[NSURL alloc] initWithString:[post.data objectForKey:@"PostImage"]];
	}
	else
	{
		url = [[NSURL alloc] initWithString:[post.data objectForKey:@"ProfileImage"]];
	}

	NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:url] delegate:self];
	self.imageConnection = connection;
	[url release];
	[connection release];
}

- (void)cancelDownload
{
	[self.imageConnection cancel];
	self.imageConnection = nil;
	self.activeDownload = nil;
}

#pragma mark -
#pragma mark Download support (NSURLConnectionDelegate)

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [self.activeDownload appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    // Clear the activeDownload property to allow later attempts
    self.activeDownload = nil;

    // Release the connection now that it's finished
    self.imageConnection = nil;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    // Set Image and clear temporary data/image
    UIImage *image = [[UIImage alloc] initWithData:self.activeDownload];

    if (image.size.width != kImageHeight && image.size.height != kImageHeight)
    {
        CGSize itemSize = CGSizeMake(kImageHeight, kImageHeight);
        UIGraphicsBeginImageContext(itemSize);
        CGRect imageRect = CGRectMake(0.0, 0.0, itemSize.width, itemSize.height);
        [image drawInRect:imageRect];
		if ([self downloadPostImage])
		{
			self.post.postImage = UIGraphicsGetImageFromCurrentImageContext();
		}
		else
		{
			self.post.profileImage = UIGraphicsGetImageFromCurrentImageContext();
		}
        UIGraphicsEndImageContext();
    }
    else
    {
		if ([self downloadPostImage])
		{
			self.post.postImage = image;
		}
		else
		{
			self.post.profileImage = image;
		}
    }

    self.activeDownload = nil;
    [image release];

    // Release the connection now that it's finished
    self.imageConnection = nil;

    // call our delegate and tell it that our icon is ready for display
    [delegate imageDidLoad:self.indexPathInTableView];
}

@end

There’s definitely room for improvement in there (you can remove some of the application specific logic) but it works well and I never had an issue with it. Let me know if you run into any problems though!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.