Core Data and threading

Persistence Senior Swift 5.5+ iOS 17+ Reviewed By Alok Singh

Pick the fix

Importing 50,000 records freezes the UI. Best approach?

Options
Hint 1 of 1

Which queue does the viewContext use?

Choose an answer, then open Show answer below to check it.

Show answer

Answer: A Import in a background context (or NSBatchInsertRequest) and let the viewContext merge changes

Correct. Work leaves the main queue and the UI updates when it's done.

Why not the others?
  • B Loop over the records on the viewContext and save every 100. It still blocks the main queue.
  • C Fetch objects on the main context and edit them from a background thread. That breaks queue confinement and causes crashes.
  • D Create a new NSPersistentContainer for each batch. Containers are expensive and don't share contexts.

30-second answer

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.

Practise saying it · 45 s. No recording, just a timer

Explain Core Data concurrency.

Say your answer out loud, then check which of these points you covered:

  • Queue-confined contexts
  • perform blocks
  • Pass object IDs
  • Background imports

Deep dive

Enable -com.apple.CoreData.ConcurrencyDebug 1 to catch violations.

Batch requests skip the context, so merge their changes explicitly.

try await context.perform { } works with async/await.

Managed objects aren't Sendable.

Common mistakes

  • Passing managed objects to another thread.
  • Importing thousands of rows on the viewContext.

Senior take & follow-ups

Seniors know the queue confinement rules and use batch operations for big imports.

Follow-up questions

Think of your answer first, then open the hint.

  1. How do you hand an object to another context?

    Show hint

    Pass its objectID and fetch it there.

  2. How do you catch threading bugs?

    Show hint

    The concurrency debug launch argument.

Suggest a fix if something here is wrong or out of date.