如何为SwiftUI的@Query宏指定不同的ModelContainer?
解决方案:通过@Query宏指定自定义ModelContainer
SwiftUI的@Query宏完全支持指定自定义的ModelContainer,不需要手动执行数据获取。你可以通过宏的container参数,传入自定义容器的环境绑定来实现。
步骤1:定义自定义容器的环境键
系统默认的modelContainer环境键专为默认容器设计,你需要为自定义的creationContainer创建专属环境键:
private struct CreationContainerKey: EnvironmentKey { static let defaultValue: ModelContainer? = nil } extension EnvironmentValues { var creationContainer: ModelContainer? { get { self[CreationContainerKey.self] } set { self[CreationContainerKey.self] = newValue } } }
步骤2:在App层级注入两个容器
将默认容器(捆绑存储)和自定义容器(可编辑存储)都注入到视图环境中:
@main struct YourApp: App { let modelContainer: ModelContainer let creationContainer: ModelContainer init() { // 初始化捆绑存储的默认容器 let readOnlySchema = Schema([ReadOnlyModel.self]) guard let bundleDataURL = Bundle.main.url(forResource: "ReadOnlyDatabase", withExtension: "momd") else { fatalError("捆绑数据库文件不存在") } self.modelContainer = try! ModelContainer(for: readOnlySchema, configurations: [ ModelConfiguration(url: bundleDataURL) ]) // 初始化可编辑的自定义容器 let editableSchema = Schema([EditableModel.self]) self.creationContainer = try! ModelContainer(for: editableSchema) } var body: some Scene { WindowGroup { ContentView() .modelContainer(modelContainer) // 注入默认容器 .environment(\.creationContainer, creationContainer) // 注入自定义容器 } } }
步骤3:在视图中用@Query指定目标容器
- 查询可编辑容器的数据时,通过
container参数传入自定义环境键:
struct EditableItemsView: View { // 指定查询creationContainer中的数据 @Query(container: \.creationContainer, sort: \EditableModel.updateTime) private var editableItems: [EditableModel] var body: some View { List(editableItems) { item in Text(item.userContent) } } }
- 查询捆绑存储容器的数据时,直接使用默认的
@Query(无需指定container参数):
struct ReadOnlyItemsView: View { // 默认使用modelContainer查询 @Query(sort: \ReadOnlyModel.id) private var readOnlyItems: [ReadOnlyModel] var body: some View { List(readOnlyItems) { item in Text(item.staticContent) } } }
关联两个容器数据的场景
如果需要基于可编辑数据的ID匹配捆绑存储中的数据,可以结合两个@Query实现:
struct CombinedDataView: View { @Query(container: \.creationContainer) private var editableItems: [EditableModel] @Query private var allReadOnlyItems: [ReadOnlyModel] var body: some View { List(editableItems) { editableItem in if let matchedReadOnlyItem = allReadOnlyItems.first(where: { $0.id == editableItem.linkedReadOnlyID }) { VStack(alignment: .leading) { Text("用户编辑内容:\(editableItem.userInput)") Text("关联静态数据:\(matchedReadOnlyItem.detail)") } } } } }
如果捆绑存储的数据量极大,全量查询影响性能,你依然可以在视图中通过自定义容器的ModelContext手动查询特定ID的数据,这种场景下手动查询是合理的,但@Query依然能覆盖大部分常规列表展示场景,减少样板代码。
内容的提问来源于stack exchange,提问作者Ash
相关产品推荐
相关产品推荐

