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!

mfaani
  • 33,269
  • 19
  • 164
  • 293
Jackky White
  • 357
  • 1
  • 4
  • 11
  • [SDWebImage](https://github.com/rs/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. – Hai Feng Kao Apr 03 '15 at 15:17
  • 3
    @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? – Jackky White Apr 03 '15 at 15:20
  • @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? – Jackky White Apr 03 '15 at 15:21
  • you can definitely do that. – Hai Feng Kao Apr 04 '15 at 15:35
  • @HaiFengKao , you think it could be efficient method? – Jackky White Apr 04 '15 at 17:57
  • It depends on the size of the images. If the size is normal(~1024x768), the performance should not be a problem. – Hai Feng Kao Apr 05 '15 at 16:58
  • @HaiFengKao , you have a skype maybe? It would be a great project to do :) – Jackky White Apr 05 '15 at 21:18
  • @HaiFengKao Two things: First, I agree with your recommendation to use something like SDWebImage. [AFNetworking](https://github.com/AFNetworking/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`. – Rob Apr 06 '15 at 17:25
  • @JackkyWhite Thanks, but I have too many projects. – Hai Feng Kao Apr 07 '15 at 03:13
  • @Rob Thanks for the info. Indeed iOS 7 changes the behavior of NSCache. – Hai Feng Kao Apr 07 '15 at 03:13

1 Answers1

51

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).

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • 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!!!!!!!!!!! – Jackky White Apr 06 '15 at 22:54
  • 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. – Rob Apr 06 '15 at 23:32
  • 1
    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? – Jackky White Apr 07 '15 at 00:27
  • @Rob do you think there is a way of getting the object from NSCache without making cache as static variable? – LC 웃 Jan 05 '16 at 16:31
  • @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. – Rob Jan 05 '16 at 17:49
  • 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? – LC 웃 Jan 05 '16 at 17:55
  • 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. – Rob Jan 05 '16 at 18:02
  • 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. – Sharad Chauhan May 30 '19 at 09:18
  • 3
    @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`](https://developer.apple.com/documentation/foundation/urlcache). – Rob May 30 '19 at 14:41
  • 1
    @Rob 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`? – Manuel Sep 11 '19 at 16:05