Core Data works, but wiring up an .xcdatamodeld file, generating NSManagedObject subclasses, and threading an NSPersistentContainer through the app is a lot of ceremony to store a handful of structs.
#The old way
import CoreData
final class Recipe: NSManagedObject {
@NSManaged var title: String
@NSManaged var servings: Int16
@NSManaged var createdAt: Date
}
let container = NSPersistentContainer(name: "RecipeModel")
container.loadPersistentStores { _, error in
if let error {
fatalError("Unresolved error \(error)")
}
}
let context = container.viewContext
let recipe = Recipe(context: context)
recipe.title = "Pancakes"
recipe.servings = 4
recipe.createdAt = .now
try? context.save()
#The new way
import SwiftUI
import SwiftData
@Model
final class Recipe {
var title: String
var servings: Int
var createdAt: Date
init(title: String, servings: Int, createdAt: Date = .now) {
self.title = title
self.servings = servings
self.createdAt = createdAt
}
}
@main
struct RecipeApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: Recipe.self)
}
}
struct AddRecipeButton: View {
@Environment(\.modelContext) private var context
var body: some View {
Button("Add Recipe") {
context.insert(Recipe(title: "Pancakes", servings: 4))
}
}
}
#Why it matters
@Modelgenerates the persistence machinery from a plain Swift class — no separate schema file to keep in sync.modelContainer(for:)wires the container and injectsmodelContextinto the environment in one call- Properties are ordinary
vars: optionals, enums, and arrays work withoutNSManagedshims - Undo support, CloudKit sync, and migrations build on the same model definitions
#Gotcha
context.insert(_:) stages the object but doesn't write it to disk — SwiftData autosaves on a schedule (and on app background), but if a write needs to be durable immediately, call try context.save() yourself. Also, @Model classes are reference types with identity tied to the persistent store: comparing two fetched instances with == compares object identity, not field values, which surprises people coming from Core Data's similarly-shaped but differently-behaved managed objects. Check exact autosave timing against current docs before relying on it for a critical write path.