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
NSCache
helps 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.
NSCache
has 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.