iOS - Best practice to save Images locally - NSCache vs Save in Document Directory
Asked Answered
S

1

21

I'm developing an app that similar to Instagram feed (tableviews with cells that contain images and some labels).

For all the data I'm getting from the database, I'm using Data Task (because it doesn't take much to receive them), but for the images (which their url's I get with the Data request), I need to save locally for future use (improve user experience).

My logic is the following: Save in NSCache or in Document Directory, the images inside folder with the date they been downloaded(create it once and append all other images if needed) (I'm deleting every folder which is not from the recent 7 days), and then for the TableView, just load if from there, so the tableview will scroll smoothly and won't load the url directly from its delegate method. So where is the better place to store them according to my needs, NSCache or Document Directory.

Looking forward to hearing your suggestions, Thank you!

Scientist answered 3/4, 2015 at 14:59 Comment(10)
SDWebImage might solve your problem. It caches image in the disk. NSCache might not be a good choice, because it will be emptied automatically when the system is low on memory.Burley
@HaiFengKao I prefer pure swift , no third party libraries . I can start build solution myself , im just looking for the correct path . Any more suggestions mate?Scientist
@HaiFengKao maybe evolve this two together? for the time he have download it store it inside NSCache , and before the image "dismiss" he will store it locally for future use?Scientist
you can definitely do that.Burley
@HaiFengKao , you think it could be efficient method?Scientist
It depends on the size of the images. If the size is normal(~1024x768), the performance should not be a problem.Burley
@HaiFengKao , you have a skype maybe? It would be a great project to do :)Scientist
@HaiFengKao Two things: First, I agree with your recommendation to use something like SDWebImage. AFNetworking also has a nice UIImageView category, much like SDWebImage. But, second, it is no longer the case that NSCache is automatically purged on memory pressure. It should, but doesn't. Both SDWebImage and AFNetworking manually register for UIApplicationDidReceiveMemoryWarningNotification and purge the cache manually, as should anyone who uses NSCache.Gavriella
@JackkyWhite Thanks, but I have too many projects.Burley
@Gavriella Thanks for the info. Indeed iOS 7 changes the behavior of NSCache.Burley
G
53

NSCache and persistent storage serve largely different purposes. NSCache holds the item in memory and is used for optimal performance. But it takes up memory (RAM) and you really should make sure that if you use NSCache that you respond to memory warnings and purge the NSCache in those cases. And when the app terminates, the NSCache is lost.

Using persistent storage cache (generally the Caches folder) is used for a different purpose, saving you from needing to re-retrieve the asset via some network request, but not holding the resource in memory. This makes it a great cache mechanism across sessions of running the app or in situations where you may have encountered memory pressure, purged the NSCache, but didn't want to re-retrieve the asset from the network.

Note that I mention the Caches folder for persistent storage, whereas you seemed to presume that one would use Documents folder, but there are two considerations:

  1. Apple is getting more particular about apps only using Documents folder for user data that cannot be easily recreated, and using Caches folder for data that is easily re-retrieved. See File System Basics for more information.

  2. Starting with iOS 11, you should only store user visible documents in the Documents folder (see WWDC 2017 Fall video, iOS Storage Best Practices). Even if you had internally used files that were not easily reconstructed, unless the intent was to eventually expose the user to them, you'd use the Application Support directory, not the Documents folder.

Bottom line, one would generally use the Caches folder for a persistent storage based cache.

Note, we'll often use a two-tier cache mechanism. Cache the resource to both NSCache and the Caches folder. Then, when you go to retrieve a resource, first check NSCache (really fast), if not there, check persistent storage, and if not there, re-retrieve the asset from the network.

Having said all of that, to make it even more complicated, there is a third type of cache, that provided by NSURLCache (i.e. responses for network requests are transparently cached by NSURLSession and NSURLConnection). This cache is dictated by poorly documented rules (e.g. it won't cache any single item whose size exceeds 5% of the total cache size) and is subject to the HTTP headers provided by the network response. This cache, though, operates largely transparently to you and provides both memory and persistent storage caches. Often you can enjoy NSURLCache caching behavior with absolutely no intervention on your part. It's seamless (when it works).

Gavriella answered 6/4, 2015 at 17:11 Comment(10)
Thanks you again for awesome answer , so just to make thing a lil big more simple - You don't recommend use Document Directory , You do recommend use a mechanism the NSCache and hos folder in the follow order : CASE 1 : check in NSCache , case 2 : Check in Cache directory , CASE 3 : download again , Follow up questions : 1) There is a limit in the Cache directory? 2) When i download it online , i immediately store it inside both CASE 1 and CASE 2? or i wait for NSCache to remove it and than append it to the Cache folder? 3) I save the images as files inside the Cache folder? Thanks!!!!!!!!!!!Scientist
The limit in the cache folder is total available persistent storage (though you might want to be a good citizen and constrain that if you're app is likely to need extraordinary amounts of storage). Personally I would always cache to persistent storage and re caching to NSCache immediately when your download, if you are doing lazy loading, yes; if doing eager loading, then probably not. And, yes, when saving to persistent storage, I'd probably write it as a file, though NSURLCache uses SQLite.Gavriella
Well at the end i have managed to come up with a "okay" efficiency soltuin , tell me what you think ::: DataTask that gets the future cells ID'S -> Check if the ID's exist in the presonal DB(Havent figured out if using NSDirectory or Core Data) -> If exist -> load the images,text etc' locally -> If not exists -> Download it -> Save it locally -> Load it locally....... No use of NSCache , only the CacheDirectory , will it decrease preference?Scientist
@Gavriella do you think there is a way of getting the object from NSCache without making cache as static variable?Vertigo
@anishparajuli - Sure, the cache doesn't care if it's a static or not. You just want it to persist throughout its useful lifespan. It's completely up to you how you accomplish that.Gavriella
but if i create a cache as var cache = NSCache() and setObject next time i get the value as nil with the cache?and if i want the object in anothe viewcontroller surely there is no way of getting the object..so i tried making that cache as static and it works ok now?Vertigo
If you want two view controllers to share a cache, you can either pursue a singleton pattern or you can store it somewhere that persists (such as app delegate or (not good) a global), or you can instantiate it and pass it around.Gavriella
Hi, I have a big doubt on this line And when the app terminates, the NSCache is lost., are you sure about this ? As I am using NSCache in my Image downloading class and when I open the app again, Images are there even if there is no internet, so I have this doubt.Thorax
@SharadChauhan - Yes, I am. In your case, either the app was just suspended and not actually terminated or it’s finding content in the NSURLCache.Gavriella
@Gavriella You write "...if you use NSCache that you respond to memory warnings and purge the NSCache in those cases." Isn't that done automatically by the system, which is the actual purpose of NSCache?Reikoreilly

© 2022 - 2024 — McMap. All rights reserved.