← All topics/Data persistence

Practical interview questions

Scenario-style prompts with sample answer outlines. Focus is on how you would design and reason in real codebases.

Question 7

SwiftData, concurrency, and data races

How do you avoid data races when reading and writing SwiftData from Swift concurrency (async/await, actors, background work)?

Answer outline

The core rule in SwiftData is to never share a ModelContext across concurrent tasks. Each context must be owned by a single execution domain — @MainActor for UI work, a dedicated background context for background operations.

Pass IDs or plain values between tasks, not live model objects. Re-fetch in the destination context before reading or mutating — this keeps each context isolated and prevents data races.

Principles

  • Never share a ModelContext — give each task or actor its own context.
  • Keep UI work on @MainActor and use a separate background context for heavy operations.
  • Pass IDs or plain values across context boundaries, not live model objects.
  • Re-fetch in the destination context before mutating — treat contexts as non-transferable.
  • Serialize writes through one owner when multiple async paths could update the same data.