# Caching image in memory or on disk

I am caching an image locally..That same image will be used in few screens. Steps for doing this is as follows:

1. Get image from cache

2. If not present in NSCache, get image from Cache directory

5. Insert the image in cache

//Helper class is as

     class ImageCacheHelper:NSObject{

static var cache = NSCache()
static var isNotRunningDispatch:Bool = true

class func setObjectForKey(imageData:NSData,imageKey:String){

ImageCacheHelper.cache.setObject(imageData, forKey: imageKey)

}

class func getObjectForKey(imageKey:String)->NSData?{

return ImageCacheHelper.cache.objectForKey(imageKey) as? NSData

}

class func getImage(imageUrl:String,completionHandler:(NSData)->()){
if ImageCacheHelper.isNotRunningDispatch{

ImageCacheHelper.isNotRunningDispatch = false
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), {
let imgUrl = NSURL(string:imageUrl)
let imageData = NSData(contentsOfURL: imgUrl!)!
ImageCacheHelper.setObjectForKey(imageData, imageKey: "\(imageUrl.hashValue)")
ImageCacheHelper.isNotRunningDispatch = true
completionHandler(imageData)

})
}else{
}
}
}


//How i call this from ViewController class is as

let userImageUrl = "\(appBaseUrl)\(imageUrlString)"
let fileManager = NSFileManager.defaultManager()
let cacheDirectory = diskPaths[0] as NSString
let diskPath = cacheDirectory.stringByAppendingPathComponent("\(userImageUrl.hashValue)")
if let data = ImageCacheHelper.getObjectForKey("\(userImageUrl.hashValue)"){
let userImage =  UIImage(data: data)
self.userImgView.image = userImage

}else if fileManager.fileExistsAtPath(diskPath){

let image =  UIImage(contentsOfFile: diskPath)
self.userImgView.image = image
ImageCacheHelper.setObjectForKey(UIImageJPEGRepresentation(image, 1.0)!, imageKey: "\(userImageUrl.hashValue)")

}else   {
ImageCacheHelper.getImage(userImageUrl){ imageData in

imageData.writeToFile(diskPath, atomically: true)
dispatch_async(dispatch_get_main_queue()){

let userImage =  UIImage(data: imageData)
self.userImgView.image = userImage

}
}
}


Flaws That I see in my code are as follows:

1. Creating a static variable for NSCache.

2. Would be great if settingObject in NSCache, getting would be as of NSUserDefaults.

How to optimize this?

Here is a snippet of project that i have tried to do https://drive.google.com/file/d/0B6dTvD1JbkgBS1k3Ry1xNmZ1VHc/view?usp=sharing

• Where in your code is an image downloaded from the Internet? – Martin R Jan 5 '16 at 18:21
• @MartinR sorry that was just anothe snippet of code..please see the edited question – LC 웃 Jan 5 '16 at 18:31

Modify Caching Strategy

It seems every image that is subject to caching is ending up both in memory and on disk. Depending on the number of images and caching aggressiveness, this could be more expensive (in terms of resource usage) than the network request used to retrieve the image.

From my perspective, using both NSCache and the Cache directory together doesn’t add any value. They are both volatile and unpredictable (to different extents). The system could reclaim space from either when it deems it necessary.

From Apples File System Programming Guide:

"Note that the system may delete the Caches/ directory to free up disk space, so your app must be able to re-create or download these files as needed.”

Therefore its either a choice between caching in memory and caching on disk or an emphasis of one over the other. This inevitably leads to additional questions about how your app will be used and the what kind of images you are working with.

Some basic guidelines:

• You don’t want to store a large number of full resolution images in memory
• You don’t want to have too many file system I/O operations (spread over time)
• You don’t want to have images in memory that are not going to be seen by the user
• You don’t want to go to disk every time for frequently seen images

What is a large number? How much is too many? You will have to test and measure.

Test & Measure (and then measure again)

I would definitely recommend testing and measuring your caching strategy to see how much of an impact it has. Xcode instruments provides tools to accomplish this.

2. Test with a simple caching strategy (maybe just using NSCache or the Cache directory)