Advertise Books Events Forum News Social Networking Support Us

sdkIQ for iPhone
($4.99)

Shape Up
($0.99)

Your First iPhone App
($1.99)

iVidCam Free
(free)

Kid Art
($0.99)

iPUBQUIZ
(£1.19)

ArtStudio
($3.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum

View Single Post
Old 06-12-2009, 02:58 PM   #1 (permalink)
CanadaDev
Registered Member
 
Join Date: Mar 2009
Location: Toronto, ON
Posts: 111
Default Asynchronous image download/caching performance issue

I will try to explain what I am trying to do and what my issue is to my best ability.

I have a UITableView, with 5-6 cells on the screen at any given time. In each cell, I have a different image (depending on the content of the cell). The image file name is obtained from an XML feed (like the rest of the cell content).

TableViewController code:

Code:
// get the string and parse it into a url to create the final image URL
NSString *param = anObject.imageFileName;
NSString *fileName = [NSString stringWithFormat:@"%@.jpg", param];
NSString *urlString = [NSString stringWithFormat: @"http://www.[redacted].com/images%@", fileName];
NSURL *imageURL = [NSURL URLWithString:urlString];

// draw a default image until an image is downloaded from URL 
UIImage *blankImage = [[UIImage imageNamed:@"blankImage.png"] retain];
cell.cellImage = blankImage;
[blankImage release];

// draw the image from URL connection or from cache (see code below)
cell.cellImageURL = imageURL;
As you can see above, I get/set the filename (so it knows what to download and what to save/retrieve the image as locally). For pretty UX I just draw a default image before the URL connection has been able to retrieve the image (if an image is found locally the change from default to local image will happen before you see it anyway).

Below is my code in my TableViewCell

Code:
- (void)setCellImageURL:(NSURL*)url
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *homeDirectoryPath = [paths objectAtIndex:0];
NSString *unexpandedPath = [homeDirectoryPath stringByAppendingString:@"/Images/"];
// folderPath is setup in the header
folderPath = [[NSString pathWithComponents:[NSArray arrayWithObjects:[NSString stringWithString:[unexpandedPath stringByExpandingTildeInPath]], nil]] retain];

if (![[NSFileManager defaultManager] fileExistsAtPath:folderPath isDirectory:NULL]) {
	[[NSFileManager defaultManager] createDirectoryAtPath:folderPath attributes:nil];
}

fileName = [[url path] lastPathComponent];
fileName = [[folderPath stringByAppendingPathComponent:fileName] retain];

// check for the image in the cache.	
if ([[NSFileManager defaultManager] fileExistsAtPath:fileName]) {
	UIImage *localImage = [[[UIImage alloc] initWithContentsOfFile:fileName] retain];
	self.cellImage = localImage;
	[localImage release];
	return;
}
	
if (connection != nil) { [connection release]; }
if (data != nil) { [data release]; }

NSURLRequest* request = [NSURLRequest requestWithURL:url
								       cachePolicy:NSURLRequestUseProtocolCachePolicy
								 timeoutInterval:60.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 {	
	[connection release];
	connection = nil;
	self.cellImage = [[UIImage imageWithData:data] retain];
	[self setNeedsDisplay];
	// save image if it's not already cached
	if (cellImage != nil) {
		CGFloat compressionQuality = 1.0;
		NSData *imageData = [NSData dataWithData:UIImageJPEGRepresentation(cellImage, compressionQuality)];
		[imageData writeToFile:fileName atomically:YES];
		
	} else {
	// if the data == nil, basically, there's no image on the server, then "re"display the default image
		self.cellImage = [[UIImage imageNamed:@"blankImage.png"] retain];
	}

	[cellImage release];
	[data release];
	data = nil;
}
I've used code from this blog: http://www.markj.net/iphone-asynchronous-table-image/ which helped me setup the asynchronous image downloading, and then I found another source for simply setting up the local folder /Images/ in the app's sandbox (which is done every time the image is called in my tableviewcontroller) and then saved in connectionDidFinishLoading:

Everything works great. EXCEPT, it's slow... I am drawing the cell, so scrolling worked flawlessly until I set up the part where I do the folderPath and save/retrieve the image on disk. I believe that's the part that slow down my table view.

The problem is, I have tried to setup the Directory and folderPath in my AppDelegate, so it just happens on app launch, but then it seems my TableViewCell is unable to get the folderPath correctly. It's just nil! And yes, I am importing the AppDelegate class, etc. correctly, because I am importing the AppDelegate class in my TableViewController and there's it's not nil.

I can provide additional code if needed. Hoping someone out there can assist. Thanks!
CanadaDev is offline   Reply With Quote
 
Enter the iPhone App Challenge!  Win $500!
» Advertisements
» Stats
Members: 24,371
Threads: 39,163
Posts: 171,679
Top Poster: smasher (2,579)
Welcome to our newest member, Oonagh
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 11:04 AM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.