Thursday, March 3, 2011

Objective C class: Simple Image Cache singleton




Your Ad Here


While working on an iPhone application which makes use of remote data and remote image assets, I realised I needed an object that could quickly and easily cache remote images in the app’s local sandboxed “Documents” folder. To be honest, I kind of feel like I reinvented someone’s wheel here, but I got exactly what I wanted – a small class (singleton) that provides full remote image (not limited to images though) caching within the sandboxed environment on an iPhone.

The class is implemented as a singleton since I can’t imagine one would want multiple storage caches running around interfering with each other.

ImageCache.h

//
//  ImageCache.h
//
//  Created by Tariq Mohammad on 03/03/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import 


@interface ImageCache : NSObject 
{
 NSString *documentsDirectory;
 NSString *cacheFileUrl;
 NSMutableDictionary *dictCache;
}

@property (nonatomic, retain) NSDictionary *dictCache;

+ (ImageCache*) instance;

- (BOOL) isRemoteFileCached:(NSString*)url;
- (NSData*) getCachedRemoteFile:(NSString*)url;
- (BOOL) addRemoteFileToCache:(NSString*)url withData:(NSData*)data;

@end
ImageCache.m

//
//  ImageCache.m//
//  Created by Tariq Mohammad on 03/03/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "ImageCache.h"

#define kDefaultCacheFile @"imagecache.plist"

//////////////////////////////////////////////////////////////////////////////////////////////////

@interface ImageCache (private)
- (NSString*) makeKeyFromUrl:(NSString*)url;
@end//private ImageCache interface

//////////////////////////////////////////////////////////////////////////////////////////////////

static ImageCache *sharedInstance = nil;

//////////////////////////////////////////////////////////////////////////////////////////////////

@implementation ImageCache
@synthesize dictCache;

////////////////////////////////////////////////////////////////////////////////

- (id)init
{
 if ( (self = [super init]) )
 {
  
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  
  documentsDirectory = [paths objectAtIndex:0];
  
  // the path to the cache map
  cacheFileUrl = [documentsDirectory stringByAppendingPathComponent:kDefaultCacheFile];
  [cacheFileUrl retain];

  dictCache = [[NSDictionary alloc] initWithContentsOfFile:cacheFileUrl];
  
  if ( dictCache == nil )
  {
   dictCache = [[NSMutableDictionary alloc] init];
  }
 }
 
 return self;
}

////////////////////////////////////////////////////////////////////////////////

- (void)dealloc
{
 [cacheFileUrl release];
 [dictCache release]
 [super dealloc];
}

////////////////////////////////////////////////////////////////////////////////

+ (ImageCache*) instance
{
 @synchronized(self)
 {
  if ( sharedInstance == nil )
  {
   sharedInstance = [[ImageCache alloc] init];
  }
 }
 return sharedInstance;
}

////////////////////////////////////////////////////////////////////////////////

- (BOOL) isRemoteFileCached:(NSString*)url
{
 NSString *imageFilename = [dictCache valueForKey:[self makeKeyFromUrl:url]];
 
 return (imageFilename != nil);
}

////////////////////////////////////////////////////////////////////////////////

- (NSData*) getCachedRemoteFile:(NSString*)url
{
 NSString *imageFilename = [dictCache valueForKey:[self makeKeyFromUrl:url]];
 NSData *data = nil;
 
 if ( imageFilename != nil )
 {
  data = [NSData dataWithContentsOfFile:imageFilename];
 }
 
 return data;
}

////////////////////////////////////////////////////////////////////////////////

- (BOOL) addRemoteFileToCache:(NSString*)url withData:(NSData*)data
{
 BOOL result = NO;
 NSString *imageFilename = [url lastPathComponent];
 
 if ( imageFilename != nil )
 {
  // the path to the cached image file
  NSString *cachedImageFileUrl = [documentsDirectory stringByAppendingPathComponent:imageFilename];

  result = [data writeToFile:cachedImageFileUrl atomically:YES];
  
  if ( result == YES )
  {
   // add the cached file to the dictionary
   [dictCache setValue:cachedImageFileUrl forKey:[self makeKeyFromUrl:url]];
   [dictCache writeToFile:cacheFileUrl atomically:YES];
  }
 }
 
 return result;
}

////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark Private Methods

- (NSString*) makeKeyFromUrl:(NSString*)url
{
 NSString *key = [url stringByReplacingOccurrencesOfString:@"/" withString:@"."];

 key = [key stringByReplacingOccurrencesOfString:@":" withString:@"."];
 return key;
}

@end

Let me know if you find this useful, or have suggestions on improving it.

 
Submit Express Inc.Search Engine Optimization Services