Core Data
Apple's object graph and persistence framework for iOS and macOS - provides SQLite-backed storage with relationships, migrations, and CloudKit sync without writing SQL
---
name: core-data
description: >
You are an iOS Core Data developer. You design managed object models, write fetch requests with NSPredicate, handle migrations, and use background contexts for heavy imports.
---Core Data is Apple's persistence framework for iOS and macOS - it sits on top of SQLite and manages an object graph with relationships, change tracking, and undo/redo. Choose Core Data over plain SQLite when you need relationship management, CloudKit sync, or Spotlight indexing out of the box; choose SwiftData for new projects targeting iOS 17+ since SwiftData uses Swift macros and eliminates most Core Data boilerplate.
Workflow
- Create a single NSPersistentContainer at app launch and share the viewContext for UI readsCreating multiple persistent containers for the same store produces separate object graphs that diverge - the viewContext is designed for UI reads on the main thread and merges changes from background contexts automatically
- Perform all heavy writes (bulk imports, JSON parsing) on a private background context via container.performBackgroundTaskWrites on the viewContext block the main thread; a background context runs on a private queue and merges its changes to the viewContext automatically when saved
- Use NSBatchInsertRequest and NSBatchDeleteRequest for operations on 1000+ objectsIndividual managed object inserts and deletes load each object into memory and trigger change notifications; batch operations bypass the object graph and run directly against SQLite, reducing memory and time by 10-100x
- Write a Core Data migration when adding, removing, or renaming an attribute - never ship a schema change without a migrationA missing migration causes NSCocoaErrorDomain Code 134100 at launch on devices with existing data, making the app crash-loop until deleted and reinstalled
- Add a NSFetchedResultsController for any list or table view backed by Core DataNSFetchedResultsController monitors the context and calls delegate methods with precise insertions, deletions, and moves - rebuilding the entire list on every context change causes UI jank
Output Format
A production Core Data stack uses NSPersistentCloudKitContainer for CloudKit sync, a viewContext for reads, background contexts for writes, and NSFetchedResultsController for UI binding.
lazy var persistentContainer: NSPersistentCloudKitContainer = {
let container = NSPersistentCloudKitContainer(name: "Model")
container.loadPersistentStores { _, error in
if let error { fatalError("Core Data: \(error)") }
}
container.viewContext.automaticallyMergesChangesFromParent = true
return container
}()Examples
Background import with batch insert
Import 10,000 JSON records into a Core Data entity
container.performBackgroundTask { context in let request = NSBatchInsertRequest(entity: Item.entity(), objects: jsonObjects); try context.execute(request) } - runs off main thread, no object-by-object memory overhead
Wrong: save on viewContext for large imports
Parsing 10,000 records and calling viewContext.save() after each
Blocks the main thread for the duration of the import, causing the UI to freeze and the watchdog to kill the app after 3-5 seconds
Right: background context with batch insert
Same import
performBackgroundTask runs on a private queue; NSBatchInsertRequest bypasses the object graph; the viewContext receives a NSManagedObjectContextDidSave notification and merges automatically
Edge Cases & Gotchas
- NSManagedObject accessed on the wrong thread - Core Data objects are thread-confined; passing a NSManagedObject across thread boundaries causes crashes; pass the NSManagedObjectID and re-fetch on the destination context
- iCloud sync conflicts - NSPersistentCloudKitContainer uses a last-write-wins conflict resolution; for user-visible data that requires merge logic, implement NSMergePolicy.mergeByPropertyStoreTrump and add a custom conflict resolver
- Migration failure on first launch after update - always test migrations with a copy of production data; lightweight migrations handle attribute additions and renaming but require an NSMappingModel for entity restructuring
When to Break These Rules
- Use SwiftData instead for new projects targeting iOS 17+ - same SQLite backend, same CloudKit sync, but with Swift macros that eliminate NSManagedObject subclasses and fetch request boilerplate
- Use plain SQLite via GRDB.swift for read-heavy workloads that need custom SQL queries or full-text search - Core Data's fetch request API does not support arbitrary SQL
Reference Files
src/data/skills/index.js- add skill entries heresrc/components/Skills/DocRenderer.js- renders this doc format