Persistence cheat sheet

The 10 Persistence interview answers in 30 seconds each, plus quick facts. Printable, free.

One page per topic: print it or save it as PDF from your browser's print menu. Practise these questions

Choosing the right storage

Choose by data type, sensitivity, size and sync needs. UserDefaults holds small preferences. The Keychain holds secrets like tokens. SwiftData or Core Data hold structured, queryable app data; SQLite or GRDB work when you want SQL. Files hold documents and media: Documents for user content (backed up), Caches for re-downloadable data (the system may purge it). CloudKit or NSUbiquitousKeyValueStore sync across devices.

Using UserDefaults correctly

Use UserDefaults for small, non-sensitive preferences such as a theme, a sort order or an onboarding flag. Wrap keys in one place (or @AppStorage in SwiftUI) to avoid typos, register defaults at launch, and use an App Group suite to share with extensions. Never store tokens or passwords there; the plist is unencrypted.

Storing secrets in the Keychain

Use the Security framework's SecItemAdd, SecItemCopyMatching, SecItemUpdate and SecItemDelete with a generic-password item identified by service and account. Choose the accessibility class deliberately: kSecAttrAccessibleWhenUnlockedThisDeviceOnly keeps a token readable only while unlocked and stops it moving to another device. Wrap the calls in a small typed store.

The Core Data stack

Your code works with NSManagedObject instances inside an NSManagedObjectContext, a scratchpad that tracks changes until you save. The context talks to an NSPersistentStoreCoordinator, which maps the managed object model to one or more NSPersistentStores, usually SQLite. NSPersistentContainer sets this up and gives you a main-queue viewContext and background contexts.

Core Data and threading

Each context belongs to one queue: the viewContext to the main queue, background contexts to their own. Only touch a context and its objects inside perform or performAndWait, and pass NSManagedObjectIDs, not objects, between contexts. Do heavy imports in a background context or with NSBatchInsertRequest, and set automaticallyMergesChangesFromParent on the viewContext.

SwiftData

SwiftData (iOS 17) is a Swift-first persistence framework built on Core Data's storage. Mark classes with @Model, create a ModelContainer with .modelContainer(for:), read with @Query in views, and insert or delete through the environment's modelContext, which autosaves. Schema versions and migration plans handle model changes.

Reading and writing files

Get a directory URL with URL.documentsDirectory (or applicationSupportDirectory or cachesDirectory), append a file name and write with data.write(to:options:). Use .atomic so a crash never leaves a half-written file, and a file protection option for sensitive data. Do large reads and writes off the main thread.

Rolling out a breaking schema change

Version the schema, prefer lightweight migrations, and use a staged or custom migration where data must be transformed. Test migrations against real copies of old stores from every supported version, run them before the UI touches data, show progress for long ones, and monitor failures. Keep a recovery path: re-sync from the server or start fresh without crashing.

Feature flags that change stored data

Separate reading from writing. First ship a version that can read both old and new formats. Only after that version is widely adopted, let the flag turn on writing the new format. Make turning the flag off safe: the app must still read data written in the new format. Remove the old path only once no supported version can produce it.

What to remove on logout

Everything tied to that account: Keychain tokens and credentials, the user's database rows, caches and files, URLCache, cookies and WKWebView website data, user-scoped UserDefaults keys and App Group data used by widgets. Also unregister the push token on the server, cancel background tasks and uploads, clear in-memory state, and remove Spotlight items and notifications.

Quick facts

NSUbiquitousKeyValueStore
Syncs small key-value data through iCloud, up to 1 MB and 1,024 keys.
@AppStorage
A SwiftUI property wrapper over UserDefaults that updates views when the value changes.
Keychain persistence
Keychain items can survive deleting the app, so don't rely on deletion to clear them.
NSFetchedResultsController
Watches a Core Data fetch and reports changes for driving lists.