SwiftData中如何在其他视图访问@Query包装的items变量?
解决SwiftData跨视图访问响应式Item数组的问题
针对你的需求,有两种简单可行的方法,既能保持数组的响应式更新,又能在addFolderSheet中访问Item列表:
方法一:在addFolderSheet中直接使用@Query
你可以在子视图中单独声明@Query来获取Item数组,只要视图能拿到modelContext(通过@Environment注入),这个查询就会自动保持响应式,和父视图的@Query一样会实时更新数据。
修改后的addFolderSheet代码:
struct AddFolderSheet: View { // Swift类型名建议大写开头 @Environment(\.dismiss) private var dismiss @Environment(\.modelContext) var modelContext @State private var name: String = "" @State private var selectedItems: Set<Item> = [] // 保存选中的Item @Query var items: [Item] // 直接声明Query获取所有Item var body: some View { NavigationStack{ Form { Section{ TextField("Folder Name", text: $name) } Section("Select Items to Sort"){ ForEach(items) { item in HStack { Text(item.itemName) Spacer() // 添加选中状态标识 Image(systemName: selectedItems.contains(item) ? "checkmark.circle.fill" : "circle") .foregroundColor(.blue) } .onTapGesture { if selectedItems.contains(item) { selectedItems.remove(item) } else { selectedItems.insert(item) } } } } } .navigationTitle("New Folder") .toolbar { ToolbarItemGroup(placement: .topBarLeading) { Button("Cancel") {dismiss()} } ToolbarItemGroup(placement: .topBarTrailing) { Button("Save") { let folder = Folder(folderName: name) // 将选中Item关联到新文件夹 for item in selectedItems { item.folder = folder // 需确保Item模型有folder关联属性 } modelContext.insert(folder) dismiss() } } } } } }
注意:需要给
Item和Folder模型设置正确的关联关系,比如在Item中添加@Relationship(inverse: \Folder.items) var folder: Folder?,在Folder中添加var items: [Item]? = []。
方法二:从父视图传递items数组
如果不想在子视图中重复写@Query,可以直接把父视图的items数组传递给addFolderSheet,父视图的items是响应式数组,传递后子视图也能实时拿到更新后的内容。
首先修改父视图的sheet调用逻辑(假设用.sheet弹出):
// 在ItemsListView的body中添加弹出按钮 @State private var showAddFolderSheet = false var body: some View { // 原有视图内容... Button("Add Folder") { showAddFolderSheet = true } .sheet(isPresented: $showAddFolderSheet) { AddFolderSheet(items: items) // 传递父视图的items数组 } }
然后修改addFolderSheet的代码:
struct AddFolderSheet: View { @Environment(\.dismiss) private var dismiss @Environment(\.modelContext) var modelContext @State private var name: String = "" @State private var selectedItems: Set<Item> = [] let items: [Item] // 接收父视图传递的数组 var body: some View { // 其余代码和方法一一致,仅去掉@Query声明 NavigationStack{ Form { Section{ TextField("Folder Name", text: $name) } Section("Select Items to Sort"){ ForEach(items) { item in HStack { Text(item.itemName) Spacer() Image(systemName: selectedItems.contains(item) ? "checkmark.circle.fill" : "circle") .foregroundColor(.blue) } .onTapGesture { if selectedItems.contains(item) { selectedItems.remove(item) } else { selectedItems.insert(item) } } } } } .navigationTitle("New Folder") .toolbar { ToolbarItemGroup(placement: .topBarLeading) { Button("Cancel") {dismiss()} } ToolbarItemGroup(placement: .topBarTrailing) { Button("Save") { let folder = Folder(folderName: name) for item in selectedItems { item.folder = folder } modelContext.insert(folder) dismiss() } } } } } }
补充说明
- 两种方法都能保持响应式:方法一通过
@Query直接监听数据变化,方法二依赖父视图传递的响应式数组自动更新。 - 确保数据模型的关联关系配置正确,否则无法完成Item到Folder的关联存储。
内容的提问来源于stack exchange,提问作者snide_forever
相关产品推荐
相关产品推荐

