Introduction
I was curious about caching data using NSCache for an iOS app. So, I did some digging. Here is what I found:
Quick Overview
NSCachehelps store data in memory. When the application gets killed, it frees memory; it’s not persisted on disk.- Storing data is carried out using a key-value pair mechanism like
Dictionary. - You can set automatic eviction to delete objects automatically.
NSCachehas multi-platform support: iOS, iPadOS, watchOS, macOS, and tvOS.
Caveats
NSCache has Objective-C roots. It can’t use struct because it is constrained to conform to AnyObject, meaning you must use class and NSString instead of String.
Store Object
You can store an object by setting it in the cache:
func storeImage(_ image: UIImage, for key: String) {
cache.setObject(image, forKey: key as NSString)
}
Retrieve Object
You can retrieve an object by getting the object for the key:
func retrieveImage(for key: String) -> UIImage? {
cache.object(forKey: key as NSString)
}
Removing Object
You can remove an object by removing the object for the key, or remove all objects:
func removeImage(for key: String) {
cache.removeObject(forKey: key as NSString)
}
func removeAllImages() {
cache.removeAllObjects()
}
Automatically Cache Cleaning
You can limit the number of objects in memory by setting countLimit. countLimit depends on the size of the object that you need to store in the cache. If it’s a large image, the limit can be less.
cache.countLimit = 5
Another way to do automatic cleaning is to set up totalCostLimit. NSCache will automatically delete objects until the total cost of the cache is under the totalCostLimit.
cache.totalCostLimit = 10 * 1024 * 1024 // 10 MB
Caveats
Even if you don’t set any deletion conditions, NSCache will automatically clean up when the system really needs memory.
NSCacheDelegate
cache(_:willEvictObject:) notifies when an object is being removed. It helps in cases when you need to react to these changes.
extension CacheService: NSCacheDelegate {
func cache(_ cache: NSCache<AnyObject, AnyObject>, willEvictObject obj: Any) {
print("Object will be evicted: \(obj)")
}
}
Complete Sample
final class CacheService: NSObject {
private let cache: NSCache<NSString, UIImage>
override init() {
cache = NSCache()
cache.name = "Remote Image Cache"
cache.countLimit = 5
cache.totalCostLimit = 10 * 1024 * 1024 // 10 MB
}
func storeImage(_ image: UIImage, for key: String) {
cache.setObject(image, forKey: key as NSString)
}
func retrieveImage(for key: String) -> UIImage? {
cache.object(forKey: key as NSString)
}
func removeImage(for key: String) {
cache.removeObject(forKey: key as NSString)
}
func removeAllImages() {
cache.removeAllObjects()
}
}
// MARK: - NSCacheDelegate
extension CacheService: NSCacheDelegate {
func cache(_ cache: NSCache<AnyObject, AnyObject>, willEvictObject obj: Any) {
print("Object will be evicted: \(obj)")
}
}
Resources
Thanks to Andy Ibanez for his amazing straightforward explanation with examples. It helped a lot to quickly understand this topic.