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.

4 comments:

  1. This comment has been removed by a blog administrator.

    ReplyDelete
  2. How to use this class

    ReplyDelete
  3.  These are wrapper classes. It should be accessible like the same way you access other wrapper classes

    ReplyDelete

 
Submit Express Inc.Search Engine Optimization Services