9
votes

I've already asked When exactly do things get removed from urlcache's memory and disk?

Now I have some more follow up questions:

  1. The memory cache is restricted by the iPhone's ram (usually 2Gb). But the disk Persistence is limited by 64Gb or 128Gb. Is that correct?

  2. Does it ever make sense to have a persistence more than your memory storage. Can it be useful if you don't want to have a high memory footprint (and don't want app to get terminated from its suspended state) ie allow the cache to be restored from disk storage and then return persisted results?

After control clicking on URLCache.shared I see the following comments:

  • Memory capacity: 4 megabytes (4 * 1024 * 1024 bytes)
  • Disk capacity: 20 megabytes (20 * 1024 * 1024 bytes)
  • Disk path:(user home directory)/Library/Caches/(application bundle id)

Users who do not have special caching requirements or constraints should find the default shared cache instance acceptable. If this default shared cache instance is not acceptable, +setSharedURLCache: can be called to set a different NSURLCache instance to be returned from this method. Callers should take care to ensure that the setter is called at a time when no other caller has a reference to the previously-set shared URL cache. This is to prevent storing cache data from becoming unexpectedly unretrievable.

Or docs

The response size is small enough to reasonably fit within the cache. (For example, if you provide a disk cache, the response [data] must be no larger than about 5% of the disk cache size.)

I included data myself

So I'm thinking my rationale is right.


How does the overall process work of reading/writing/restoring of cache work?

  1. I mean when I make a network request for the first time then is it that the entire response/error/data gets written/stored in cache and then into persistence?

  2. Next time if I want read then it first starts from the cache then if the response was not stale/expired then it will return it. Nothing would change for disk storage.

    If it was expired then it would make a new request and only upon getting a successful response, it would purge the response from memory and disk and write the new response into cache and disk. If the new request failed then it won't purge, rather it would just keep stale/expired data so if we wanted (to load expired response) it would load from there?

  3. And when app is terminated the memory is flushed out. Disk storage is left intact unless device was low on memory or you've reached size limit. Upon next launch of app, the memory reloads whatever's in the disk storage into the cache.

    This cache restoration will start loading the latest data is has stored then move onto the data that was older until it either reaches its size limit or just reach the end of the items stored on the disk. Right?

  4. If on a normal day the amount of networking a user does for a typical 1 hour session is about 30mb then should I set my cache size to 20mb and 30mb of disk storage? What if I have images? I've heard that images are stored differently as in a 1mb image can take 10mb of size. So how should I manage that?

I'm asking all this because I want to improve the caching experience in an app and improve my overall understanding so I won't increase the memory usage* of the app too much so it won't get flushed out of the memory from its suspended state due my apps high memory usage or other apps being in need.


*: some of our network requests will be downloading thumbnails, so I need to be considerate when I'm increasing my caching size limit.

1
EDIT on bounty description: ...Last but not least, if URLCache is offering such a cache service (for image caching) with such ease then why are there any third party frameworks? What benefits do they have?Honey

1 Answers

4
votes

If you want to get to know deep about memory management, you should dive into lower level APIs. URLSession, URLCache and etc. are very high level APIs. There are plenty of WWDC sessions out there about memory frames, Image caching, network caching and etc. Each part has a lot of explanation. I'm suggesting you to watch all WWDC videos (if you hadn't) for start and warm up. Some of theme has great explanation about the core concepts like this.

check out these two from this year WWDC:

Image and Graphics Best Practices

iOS Memory Deep Dive

We can sit here and discuss about your questions for weeks! But for quick answer:

  1. Yes. Memory limited due the ram size and disk limited due the storage size. The device and iOS can play with the maximum limit a bit due their needs.
  2. Exactly and this is one of the main goals of using disk. There is a concept named Swap Memory (for more investigate and R&D if you want)

Compressed data temporarily moved to disk to make room in memory for more recently used data

But memory has it own cache in its frames. Sometimes caching reduce performance instead of improving it. Because of it's frames.

  1. Not always. By default, only success requests will cache (If server not requested the client to "don't cache it" in the header). But as you may know, URLSession has plenty of configuration for caching on disk, memory and etc. in a very high level API. See URLSession Documentation.

  2. See NSURLRequestCachePolicy documentation. And this is a good tutorial about it.  NSURLRequestCachePolicy Based on the policy you chose, it behaves different and can purge the previous cache or keep it until next success.

  3. The HomeDirectory contains some main directories. iOS behaves differently with each one. iOS will only clean the the tmp directory (where the disk cache lives). You can store cache in a different directory like Documents to prevent iOS from removing it. But the point is the meaning of the cache word itself.

  4. Any less space or even more space from the actual need is critical. It can corrupt the process or waste the memory/disk. Remember the reason of link lists invention? You can have different caches for different purposes like images and JSONs. But the point about images is:

Image Memory Use

These are all at the heart of the Foundation framework and all known third parties are just wrappers around them. So the only benefits they have are: Predefined defaults based on the thousands of contributors knowledge and higher level APIs.

Alamofire and Kingfisher are great examples of them.

Conclusion

The right cache size depends on the use case. Depends on number of data variants, images count, size of each image, how often is the same image accessed and etc. for example if you are constantly changing the image in the cache, it could actually have an adverse effect on the battery life! The best way to decide on an appropriate cache size is to test. Run the app under Instruments to measure both performance and battery usage. Keep increasing the cache size until you can't discern a difference in performance. That's the largest size you'd need, at least under the test conditions. Then reduce the size until performance is just barely acceptable to determine the smallest acceptable size. The right size is somewhere between those two sizes, depending on what you think is important.