iOS: Caching images in memory

This is a repost from my previous blog that got several favorable comments.

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…)

Related Posts Plugin for WordPress, Blogger...

3 thoughts on “iOS: Caching images in memory

  1. Ian Ferguson

    thanks, this is a simple way of caching images. I’m downloading facebook newsfeed stuff so this is all I require for the app.

    cheers

    Ian

    Reply
  2. Jaminyah

    uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[__NSDictionary setObject:forKey:]: attempt to insert nil key.

    This code works fine with cache set to NO. However creates an exception with cache set to YES.
    line [staticImageDictionary setObject:retImage forKey:imageNamed]; cases a failure.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *


7 × four =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>