NSCache
iOS development
memory management
caching
Swift programming

How to use NSCache

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

NSCache is an in-memory cache class for Apple platforms that automatically evicts objects under memory pressure. It is a strong choice for temporary objects such as decoded images or computed results. Compared with a plain dictionary, NSCache is better suited for memory-sensitive apps.

Core Behavior of NSCache

NSCache stores key and value pairs and can evict entries at any time. Your app should treat cached values as optional and recomputable. This behavior is ideal for performance optimization, not for persistent storage.

In Swift, keys are typically NSString when using generic NSCache types.

swift
1import Foundation
2
3final class TextCache {
4    private let cache = NSCache<NSString, NSString>()
5
6    func set(_ value: String, for key: String) {
7        cache.setObject(value as NSString, forKey: key as NSString)
8    }
9
10    func get(_ key: String) -> String? {
11        cache.object(forKey: key as NSString) as String?
12    }
13}
14
15let c = TextCache()
16c.set("hello", for: "greeting")
17print(c.get("greeting") ?? "miss")

Configure Size Limits

You can bound cache growth with countLimit and totalCostLimit. This helps control memory usage for large values such as images.

swift
1import UIKit
2
3final class ImageCache {
4    let cache = NSCache<NSString, UIImage>()
5
6    init() {
7        cache.countLimit = 200
8        cache.totalCostLimit = 50 * 1024 * 1024
9    }
10
11    func set(image: UIImage, for key: String) {
12        let cost = Int(image.size.width * image.size.height * image.scale * image.scale)
13        cache.setObject(image, forKey: key as NSString, cost: cost)
14    }
15
16    func image(for key: String) -> UIImage? {
17        cache.object(forKey: key as NSString)
18    }
19}

For cost calculations, use an estimate that is consistent across your app.

Build a Thread-Safe Loader with NSCache

NSCache is thread-safe for basic operations, so it pairs well with asynchronous loading.

swift
1import Foundation
2
3final class UserCache {
4    private let cache = NSCache<NSString, NSString>()
5
6    func userName(id: String, load: () -> String) -> String {
7        if let value = cache.object(forKey: id as NSString) {
8            return value as String
9        }
10
11        let fresh = load()
12        cache.setObject(fresh as NSString, forKey: id as NSString)
13        return fresh
14    }
15}
16
17let users = UserCache()
18let name = users.userName(id: "42") {
19    return "Ada"
20}
21print(name)

The loader pattern centralizes cache hits and misses and keeps call sites clean.

When to Use NSCache Versus Dictionary

Use NSCache for disposable performance data that can be rebuilt. Use a dictionary when you need strict retention and predictable eviction rules managed by your own code. In many apps, both are useful for different layers.

If cache misses are expensive, combine NSCache with disk caching for a two-level strategy.

Eviction Observation with NSCacheDelegate

When tuning cache limits, it is useful to observe evictions. NSCacheDelegate gives you a callback when objects are removed.

swift
1import Foundation
2
3final class CacheObserver: NSObject, NSCacheDelegate {
4    func cache(_ cache: NSCache<AnyObject, AnyObject>, willEvictObject obj: Any) {
5        print("Evicting object: \(obj)")
6    }
7}
8
9let cache = NSCache<NSString, NSString>()
10let observer = CacheObserver()
11cache.delegate = observer
12cache.countLimit = 1
13cache.setObject("first", forKey: "a")
14cache.setObject("second", forKey: "b")

This insight helps verify whether limits are too strict or too loose.

Design a Stable Cache Key Strategy

Cache misses often come from inconsistent keys, not from eviction. Define a single key format for each cached type. For image caching, include parameters that change output such as width, scale, and style variant.

A predictable key strategy improves hit rates and avoids duplicate memory usage for equivalent values.

Use Cache Plus Source of Truth

Treat NSCache as a fast layer in front of persistent storage or network fetches. On cache miss, read from the source of truth and refill the cache. This layered pattern gives both speed and correctness.

Common Pitfalls

  • Assuming cached values will remain forever.
  • Using cache as source of truth for business-critical data.
  • Forgetting to set limits for large object workloads.
  • Storing objects that are expensive to recreate but not handling cache misses.

Summary

  • NSCache provides memory-aware in-memory caching on Apple platforms.
  • Treat cache entries as optional and rebuildable.
  • Use count and cost limits to control memory growth.
  • Keep cache logic centralized for easier maintenance.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.