在 SwiftData
中,你可以定义模型之间的关系,并且可以执行对象关联查询。这类似于 Core Data 中的关系模型。在下面的示例中,我们将新增一个 User
模型,并创建与 TodoItem
的关联关系。
1. 定义数据模型
新增一个 User
模型,并创建与 TodoItem
的一对多关系。
import SwiftData
@Model
class User {
@Attribute(.primaryKey) var id: UUID
var name: String
var todos: [TodoItem] = []
init(id: UUID = UUID(), name: String) {
self.id = id
self.name = name
}
}
@Model
class TodoItem {
@Attribute(.primaryKey) var id: UUID
var title: String
var isCompleted: Bool
@Relationship var user: User? // Optional relationship to User
init(id: UUID = UUID(), title: String, isCompleted: Bool = false, user: User? = nil) {
self.id = id
self.title = title
self.isCompleted = isCompleted
self.user = user
}
}
2. 配置数据上下文
确保 User
模型也被添加到 modelContainer
中。
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(for: [User.self, TodoItem.self])
}
}
}
3. 使用关联查询
现在我们可以在 ContentView
中通过关联查询来获取特定用户的 TodoItem
列表。以下是如何使用 @Query
执行关联查询的示例:
import SwiftUI
import SwiftData
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
@State private var selectedUser: User?
@State private var newItemTitle: String = ""
var body: some View {
NavigationView {
VStack {
// User selection (for demo purposes)
if let users = try? modelContext.fetch(User.all()) {
Picker("Select User", selection: $selectedUser) {
ForEach(users, id: \.id) { user in
Text(user.name).tag(user as User?)
}
}
.pickerStyle(MenuPickerStyle())
.padding()
}
// Display todo items for the selected user
if let user = selectedUser {
List {
ForEach(user.todos) { item in
HStack {
Text(item.title)
Spacer()
Button(action: {
toggleCompletion(for: item)
}) {
Image(systemName: item.isCompleted ? "checkmark.circle.fill" : "circle")
}
.buttonStyle(PlainButtonStyle())
}
}
.onDelete(perform: deleteItems)
}
HStack {
TextField("New todo", text: $newItemTitle)
.textFieldStyle(RoundedBorderTextFieldStyle())
.padding()
Button(action: { addItem(for: user) }) {
Image(systemName: "plus")
.padding()
}
}
}
}
.navigationTitle("Todo List")
}
}
private func addItem(for user: User) {
let newItem = TodoItem(title: newItemTitle, user: user)
modelContext.insert(newItem)
newItemTitle = ""
}
private func toggleCompletion(for item: TodoItem) {
item.isCompleted.toggle()
}
private func deleteItems(at offsets: IndexSet) {
if let user = selectedUser {
for index in offsets {
let item = user.todos[index]
modelContext.delete(item)
}
}
}
}
4. 解释代码
@Relationship
: 在TodoItem
模型中,使用@Relationship
来表示与User
的关系。user
是一个可选属性,表示任务可能没有分配给任何用户。@Query
: 你可以在@Query
中使用过滤条件来获取与特定User
相关的TodoItem
,或者在这种情况下,通过user.todos
直接访问特定用户的任务列表。- 用户选择: 在示例中,我们提供了一个用户选择器(
Picker
),用于选择查看其待办事项的用户。
5. 总结
- 关系模型: 通过
@Relationship
属性,可以轻松地定义模型之间的关系,并在 SwiftData 中管理这些关系。 - 关联查询: 使用
@Query
或直接通过关系属性(如user.todos
)来执行关联查询,从而获取相关的对象数据。
这样,你可以在 SwiftUI 中有效地管理和查询关联数据。