Mobile Development5 min read

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

iOSApplePersistenceSwiftORM
---
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

  1. 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
  2. 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
  3. 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
  4. 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
  5. 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

Input

Import 10,000 JSON records into a Core Data entity

Output

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

Input

Parsing 10,000 records and calling viewContext.save() after each

Output

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

Input

Same import

Output

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 here
  • src/components/Skills/DocRenderer.js - renders this doc format

More skills in this library

Browse all technical skills - Mobile, AI/ML, Web, Backend, Design, and Product.