SwiftData中@Model与@Published/ObservableObject共存及视图更新问题
问题解答
1. @Model与@Published/ObservableObject能否同时使用?
不能。@Model修饰的类,其属性会被SwiftData自动转换为计算属性(底层关联SwiftData的存储系统),而@Published无法应用在计算属性上,这就是你触发"Property wrapper cannot be applied to a computed property"错误的原因。
另外,@Model类本身已被SwiftData赋予可观察能力,完全不需要额外实现ObservableObject协议,SwiftData会自动跟踪属性变化并通知视图更新。
2. 解决视图不实时更新的方案
场景一:按钮修改score无实时反馈
你当前代码里的score是局部变量,修改它不会影响PracticeData实例的真实值,自然无法触发视图更新。正确做法是直接绑定PracticeData实例并修改其属性:
var body: some View { List { Section { ForEach(lesson.vocab) { vocab in // 用@Bindable包装实例,让SwiftData跟踪属性变化 @Bindable var practiceData = vocab.practiceData HStack { Text("\(practiceData.score)") Button("addToScore") { // 直接修改实例的score属性 practiceData.score += 1 // 如需立即持久化到存储,可添加: // try? modelContext.save() } } } } } }
场景二:弹窗关闭后底层视图不更新
弹窗中修改results和latestResult时,要确保操作的是同一个SwiftData上下文里的PracticeData实例,让变化被视图感知:
- 在弹窗视图中用
@Bindable包装传入的实例:
struct ResultSheetView: View { @Bindable var practiceData: PracticeData @Environment(\.dismiss) var dismiss var body: some View { Button("添加结果") { // 修改实例属性 practiceData.results.append(PracticeResult(...)) practiceData.latestResult = true dismiss() } } }
- 弹出弹窗时直接传入目标实例:
// 底层视图触发弹窗的代码 Button("打开弹窗") { sheetPresented = true } .sheet(isPresented: $sheetPresented) { ResultSheetView(practiceData: vocab.practiceData) }
- 确保底层视图的数据源(比如
lesson.vocab)是通过SwiftData的@Query获取的,这样PracticeData变化时,@Query会自动刷新视图。如果是手动传递的静态数组,需改为从SwiftData查询获取。
内容的提问来源于stack exchange,提问作者trsommer
相关产品推荐
相关产品推荐

