Some favorite site feeds aggregated locally: iPhone Development RSS   Adobe Labs RSS   Macrumors RSS

Wednesday, May 13, 2009

iPhone: Caching images in memory

Wednesday, May 13, 2009   

I have a UITableView where each cell contains a UIImageView and the contents of that are populated from a URL. This works great until you start to scroll the table, because as cells are reused they of course fetch the appropriate image through appropriate URL (updating the cell's UI), and thus cause the table to chug as it tries to scroll it.

So image caching is required. Once a URL image has been downloaded and when it's going to be used again, instead of fetching the image from URL, use a stored version of it instead. Currently I am caching these images in a NSMutableDictionary (although they could be written to the iPhone disk or into a database on the iPhone as well - for offline use and also a retained cache between application launches). While the latter approach is the ultimate correct one, here is a method to provide in-memory image caching. The key for each UIImage is the URL of the image.
- (UIImage*)imageNamed:(NSString*)imageNamed cache:(BOOL)cache
{
UIImage* retImage = [staticImageDictionary objectForKey:imageNamed];
if (retImage == nil)
{
retImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageNamed]]];
if (cache)
{
if (staticImageDictionary == nil)
staticImageDictionary = [NSMutableDictionary new];

[staticImageDictionary setObject:retImage forKey:imageNamed];
}
}
return retImage;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
// Add a view for the image (this is in section if cell = nil)
NSString *tmp = [NSString stringWithFormat:@"%@", [[photoArray objectAtIndex:row] objectForKey:@"url"]];
holder = [[[UIImageView alloc] initWithFrame:CGRectMake( 13, 2, 48, 50)] autorelease];
holder.tag = 4;
holder.contentMode = UIViewContentModeScaleToFill;

// Here we either load from the web or we cache it...
UIImage *ret = [self imageNamed:tmp cache:YES];
holder.image = ret;
...
[cell.contentView addSubview:holder];
...
This works GREAT so far, you get a little initial stutter on long lists, but once the images are loaded up, you're good to go. Since I am not currently using tons of images, memory should be okay (to keep them all around like this). Of course using the disk is going to be the ultimate solution... one I will work up next. Even for small lists it might be okay to use (if you don't plan on the images changing much...)
 
 Return to the main page
Comments:

There are currently 2 Comments:

Blogger CRS said...
“Hi,

Could you post the complete code?
This looks very useful but it difficult to fill in the missing pieces”
 
Blogger Rafael Oliveira said...
March 25, 2010 6:02 PM
“Man, I simply love you and your caching code!”
 
 Leave a comment