What is NSCache?

NSCache is part of the Foundation framework in Swift and Objective-C. It’s designed to store and manage temporary, non-persistent key-value pairs in your application. The key differentiator of NSCache from other collections like Dictionary is its automatic eviction policy. When memory pressure occurs, NSCache can automatically remove objects from its storage based on various factors, such as access frequency or the object’s cost.

class NSCache<KeyType, ObjectType> : NSObject where KeyType : AnyObject, ObjectType : AnyObject

Swift Docs-NSCache

Why Use NSCache?

Here are some reasons why you should consider using NSCache in your Swift projects:

  1. Memory Management: NSCache is designed for efficient memory management. It can automatically remove objects from its cache when system memory is limited, reducing the likelihood of your app being terminated due to memory pressure.

  2. Thread-Safe: NSCache is thread-safe, making it suitable for use in multi-threaded applications. You can safely access and modify the cache from multiple threads without worrying about synchronization issues.

  3. Customizable Eviction Policy: You can customize the eviction policy of NSCache by setting properties like countLimit (maximum number of objects) and totalCostLimit (maximum total cost of objects). This allows you to control how the cache behaves under memory pressure.

  4. Automatic Removal: NSCache can automatically remove objects that haven’t been accessed for a while, ensuring that you’re not holding onto unnecessary data.

Using NSCache in Swift

Let’s dive into some practical examples of how to use NSCache in Swift.

Example 1: Caching Images

import UIKit

let imageCache = NSCache<NSString, UIImage>()

// To store an image in the cache
func cacheImage(image: UIImage, forKey key: String) {
    imageCache.setObject(image, forKey: key as NSString)
}

// To retrieve an image from the cache
func getImage(forKey key: String) -> UIImage? {
    return imageCache.object(forKey: key as NSString)
}

In this example, we use NSCache to cache images in a simple image caching system. Images are stored and retrieved using keys, and the cache will automatically manage memory as needed.

Example 2: Caching Data with Cost Limits

let dataCache = NSCache<NSString, NSData>()

// Set a total cost limit (in bytes)
dataCache.totalCostLimit = 10 * 1024 * 1024 // 10 MB

// To store data in the cache with a cost
func cacheData(data: NSData, forKey key: String, cost: Int) {
    dataCache.setObject(data, forKey: key as NSString, cost: cost)
}

// To retrieve data from the cache
func getData(forKey key: String) -> NSData? {
    return dataCache.object(forKey: key as NSString)
}

In this example, we set a total cost limit for the cache to ensure that it doesn’t consume too much memory. Objects are cached with associated costs, and when the total cost limit is reached, the cache will start evicting objects based on their costs.

Example 3: Custom Eviction Policy

let customCache = NSCache<NSString, AnyObject>()

// Set a maximum object count limit
customCache.countLimit = 100

// To store an object in the cache
func cacheObject(object: AnyObject, forKey key: String) {
    customCache.setObject(object, forKey: key as NSString)
}

// To retrieve an object from the cache
func getObject(forKey key: String) -> AnyObject? {
    return customCache.object(forKey: key as NSString)
}

In this example, we customize the cache by setting a maximum object count limit. When the count limit is reached, the cache will automatically evict objects based on the access pattern.

Using the Cache Functions

Now, let’s create a function to use the cache functions and print the results:

func useCache() {
    let image = UIImage(named: "example.jpg") // Load an image
    let imageData = NSData() // Create NSData from the image data
    let key = "exampleKey"
    
    // Cache an image and data
    cacheImage(image: image, forKey: key)
    cacheData(data: imageData, forKey: key, cost: imageData.length)
    
    // Retrieve and print the cached image and data
    if let cachedImage = getImage(forKey: key) {
        print("Cached image size: \(cachedImage.size)")
    }
    
    if let cachedData = getData(forKey: key) {
        print("Cached data size: \(cachedData.length) bytes")
    }
}

// Call the function to use the cache
useCache()

In this function, we cache an image and data and then retrieve and print them. You can customize this function and use it to work with your specific data.

Conclusion

NSCache is a valuable tool for managing memory and improving the performance of your Swift applications. Whether you’re caching images, data, or other objects, understanding how to use NSCache effectively can help you create efficient and responsive apps. Remember to customize its eviction policy to suit your specific use case and optimize your app’s memory usage. Thanks for reading!