Question 3
Caching strategy
How do you design a caching strategy for network data (such as memory vs disk vs database), and how do you decide what to cache?
Answer outline
Start by matching each kind of data to one of three storage tiers:
- 1.Memory (
NSCache, in-process stores): fastest access, and gone when the process dies. Use it for decoded images and the session's data models. - 2.Disk (files,
URLCache): survives restarts, so it suits large blobs and structured data, and a schema version in each key retires old entries after a migration. Keep each response's ETag (entity tag) so the next request can sendIf-None-Matchand get 304 Not Modified instead of the full body. - 3.Database (Core Data, SwiftData, or a SQLite wrapper such as GRDB): best when you need queries, relationships, or incremental updates rather than key-value blobs. Treat it as the source of truth while offline, with a clear rule for when a row counts as stale.
To back URLSession with disk caching, give URLCache memory and disk budgets and attach it to a URLSessionConfiguration:
Configuring URLCache for URLSession
let memoryCapacity = 50 * 1_024 * 1_024 // 50 MB in RAM
let diskCapacity = 200 * 1_024 * 1_024 // 200 MB on disk
let cacheDir = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first
let cache = URLCache(
memoryCapacity: memoryCapacity,
diskCapacity: diskCapacity,
directory: cacheDir
)
// Attach the cache to a session configuration
let config = URLSessionConfiguration.default
config.urlCache = cache
// Cache first: serve any cached copy regardless of age, with no revalidation.
// The default .useProtocolCachePolicy honors Cache-Control and ETag headers instead.
config.requestCachePolicy = .returnCacheDataElseLoad
let session = URLSession(configuration: config)
Cache resources that are read often and need to show immediately, plus content the user explicitly saves or revisits. Don't cache sensitive data without encryption, and keep secrets in the Keychain rather than in any cache.
Principles
- Set a policy per resource: TTL (time to live), size cap, invalidation on logout, and an ETag or version check.
- Use stale-while-revalidate for feeds: show the cached copy immediately, then refresh in the background when online.
- Give each cache a single writer, such as an actor or a serial queue, so concurrent updates can't race.
- Cache what's read often and slow to fetch, and leave tokens and secrets to the Keychain.



