How to make NSCache do its job
Recently, I needed to add caching to one of the iOS apps I’m working on. While
researching a few possible ways how to go about this I came across a great
article written by John Sundell
(a pretty common occurrence when searching
for Swift topics on the web, thanks John!). While the basic concept he describes
in the article worked quite well for my needs, there was one major problem with
the approach: NSCache
will drop your objects like hot potatoes as soon as your
app gets backgrounded.
This behavior essentially nullifies the purpose of implementing caching in the
first place. I guess most developers have the same assumptions as I had about how
NSCache
behaves:
- When memory is needed, the system will automatically remove objects from your cache.
- Your cached objects survive your app being backgrounded
As already mentioned, the latter isn’t true. At least not for the particular implementation described in the original article.
Luckily, there’s an easy yet somehow undocumented fix for this situation. This StackOverflow answer pointed me in the right direction. The user writes:
In addition, based on source of NSCache.m I found here, objects that do not conform to NSDiscardableContent protocol are never removed at runtime even the app needs more memory and should evict some of its elements. Maybe that’s the reason why non-NSDiscardableContent objects are evicted when the app is entering background because that’s a good time for them to be evicted.
So if you don’t want the system to evict all objects from your cache when your
app gets backgrounded, make sure your objects implement the
NSDiscardableContent
protocol.
In case of John’s original example, conforming to NSDiscardableContent
is
quite trivial:
private extension Cache: NSDiscardableContent {
final class Entry {
let value: Value
init(value: Value) {
self.value = value
}
func beginContentAccess() -> Bool { true }
func endContentAccess() { }
func discardContentIfPossible() { }
func isContentDiscarded() -> Bool { false }
}
}
Enjoy your data waiting for you in the cache after you come back from liking stuff on Instagram!