Model Definition
What is SwiftData?
SwiftData is Apple's modern persistence framework introduced in iOS 17. It uses the @Model macro to define persistent objects that integrate seamlessly with SwiftUI.
Defining a Model
import SwiftData
@Model
class Article {
var id: UUID
var title: String
var content: String
var publishedAt: Date
var isPublished: Bool
init(title: String, content: String) {
self.id = UUID()
self.title = title
self.content = content
self.publishedAt = Date()
self.isPublished = false
}
}
The @Model macro generates persistence code automatically.
Model Container
Set up the container in your App:
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: Article.self)
}
}
Model Context
Access the context to save and fetch:
struct ContentView: View {
@Environment(\.modelContext) private var context
func addArticle() {
let article = Article(title: "New", content: "Hello")
context.insert(article)
try? context.save()
}
}
Default Values
Provide defaults for model properties:
@Model
class Settings {
var theme: String = "light"
var notificationsEnabled: Bool = true
var fontSize: Double = 16.0
}
Queries & Fetching
@Query Property Wrapper
@Query fetches data automatically and keeps it in sync:
struct ArticleListView: View {
@Query(sort: \Article.publishedAt, order: .reverse)
private var articles: [Article]
var body: some View {
List(articles) { article in
Text(article.title)
}
}
}
Filtering Queries
@Query(filter: #Predicate<Article> { article in
article.isPublished == true
}, sort: \Article.publishedAt)
private var publishedArticles: [Article]
Dynamic Queries
Use FetchDescriptor for dynamic filtering:
struct SearchView: View {
@State private var searchText = ""
@Query private var articles: [Article]
var filteredArticles: [Article] {
if searchText.isEmpty { return articles }
return articles.filter { $0.title.localizedCaseInsensitiveContains(searchText) }
}
}
FetchDescriptor
For complex queries:
let descriptor = FetchDescriptor<Article>(
predicate: #Predicate { $0.isPublished == true },
sortBy: [SortDescriptor(\Article.publishedAt, order: .reverse)]
)
let articles = try modelContext.fetch(descriptor)
Aggregate Queries
let count = try modelContext.fetchCount(descriptor)
Batch Operations
try modelContext.delete(model: Article.self, where: #Predicate { $0.isPublished == false })
Relationships & Migrations
One-to-Many Relationships
@Model
class Author {
var name: String
@Relationship(deleteRule: .cascade)
var articles: [Article]
init(name: String) {
self.name = name
self.articles = []
}
}
@Model
class Article {
var title: String
var author: Author?
}
Delete Rules
.nullify- Set relationship to nil (default).cascade- Delete related objects.deny- Prevent deletion if related objects exist
Versioned Model Migration
enum SchemaV1: VersionedSchema {
static var versionIdentifier = Schema.Version(1, 0, 0)
static var models: [any PersistentModel.Type] {
[Article.self]
}
}
enum SchemaV2: VersionedSchema {
static var versionIdentifier = Schema.Version(2, 0, 0)
static var models: [any PersistentModel.Type] {
[Article.self]
}
static func migrate(_ migration: SchemaMigrationPlan) {
migration.addSchema(Article.self)
}
}
let container = try ModelContainer(
for: Article.self,
configurations: ModelConfiguration(schema: Schema([Article.self]))
)
Custom Migration
let migration = SchemaMigrationPlan("v1_to_v2")
migration.stage(fromVersion: SchemaV1.self, toVersion: SchemaV2.self) { context in
// Custom migration logic
}
Quiz
1. What macro defines a SwiftData model?
2. How do you access the model context in SwiftUI?
3. What does @Query do in SwiftUI?
4. What delete rule removes related objects?
Flashcards
Question
What is SwiftData?
Click to reveal answer
Answer
Apple's modern persistence framework (iOS 17+) using the @Model macro for automatic Swift object persistence.
Question
How do you set up a model container?
Click to reveal answer
Answer
Use .modelContainer(for: Type.self) on the Scene in your App.
Question
What is the difference between @Query and FetchDescriptor?
Click to reveal answer
Answer
@Query is a property wrapper for SwiftUI. FetchDescriptor is for imperative fetching in non-SwiftUI code.
Question
How do you filter queries in SwiftData?
Click to reveal answer
Answer
Use #Predicate for type-safe filtering or filter: parameter in @Query.
Revision Notes
Key Takeaways
- 1. @Model macro generates persistence code automatically for SwiftData models
- 2. @Query provides automatic, synced data fetching in SwiftUI views
- 3. @Environment(\.modelContext) is used for insert, save, and delete operations
- 4. Relationships use @Relationship with delete rules (.cascade, .nullify, .deny)
- 5. VersionedSchema enables safe data model migrations
Interview Tips
- • Explain how SwiftData simplifies persistence compared to Core Data
- • Know the difference between @Query and FetchDescriptor
- • Describe how to set up and use model containers
- • Discuss migration strategies with VersionedSchema
Cheat Sheet
@Model macro defines persistent models. @Query fetches data automatically. @Environment(.modelContext) for CRUD. .modelContainer(for:) on Scene. #Predicate for filtering. .cascade delete rule removes related objects. VersionedSchema for migrations.