patternswiftMinor
Caching image in memory or on disk
Viewed 0 times
diskcachingimagememory
Problem
I am caching an image locally..That same image will be used in few screens. Steps for doing this is as follows:
-
Get image from cache
-
If not present in NSCache, get image from Cache directory
-
If not present in Cache Directory, download from Internet
-
Save downloaded image to dir
-
Insert the image in cache
//Helper class is as
//How i call this from ViewController class is as
```
let userImageUrl = "\(appBaseUrl)\(imageUrlString)"
let fileManager = NSFileManager.defaultManager()
let diskPaths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let cacheDirectory = diskPaths[0] as NSString
let diskPath = cacheDirectory.stringByAppendingPathComponent("\(userImageUrl.hashValue)")
if let data = ImageCacheHelper.
-
Get image from cache
-
If not present in NSCache, get image from Cache directory
-
If not present in Cache Directory, download from Internet
-
Save downloaded image to dir
-
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{
print("alerady started loading image")
}
}
}//How i call this from ViewController class is as
```
let userImageUrl = "\(appBaseUrl)\(imageUrlString)"
let fileManager = NSFileManager.defaultManager()
let diskPaths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.CachesDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let cacheDirectory = diskPaths[0] as NSString
let diskPath = cacheDirectory.stringByAppendingPathComponent("\(userImageUrl.hashValue)")
if let data = ImageCacheHelper.
Solution
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
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:
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.
One way to go about this is:
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.
One way to go about this is:
- Test with no cache (this will be your baseline)
- Test with a simple caching strategy (maybe just using
NSCacheor the Cache directory)
- Compare the results of step 2 to your baseline obtained from step 1
- Not satisfied, then apply a different caching strategy. Repeat step 3. Otherwise, if you are satisfied with the resource usage and responsiveness of the app then you can stop here until there are significant changes to either your codebase, data or the iOS frameworks.
Context
StackExchange Code Review Q#115908, answer score: 3
Revisions (0)
No revisions yet.