You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI List内嵌GoalView未随ObservedObject数据源更新问题求解

问题根因

你遇到的问题核心来自两个逻辑的共同作用:

  1. 你当前ForEach的标识规则仅匹配GoalWrapper的id属性,只要id不变,SwiftUI就会判定该位置的视图不需要重新初始化,只会复用已有的GoalView实例,也就不会更新传入的goalWrapper参数。
  2. 你的AppConnectivityManager更新goals数组时,是生成了新的GoalWrapper实例,而不是修改原有数组中GoalWrapper实例的goal属性。这就导致已有的GoalView持有的还是旧的GoalWrapper对象,旧对象的goal属性从未更新,自然不会触发视图刷新。而父视图的ForEach因为遍历的是新数组,所以print会输出最新值。

解决方案

以下方案按推荐优先级排序:

方案1(最推荐):修改数据更新逻辑,复用原有GoalWrapper实例

不要在更新数据时直接替换goals数组的元素,而是找到对应id的原有GoalWrapper实例,直接修改它的goal属性:

// 示例更新逻辑,写在AppConnectivityManager内部
func updateGoal(_ newGoal: Goal) {
    if let index = goals.firstIndex(where: { $0.id == newGoal.id }) {
        goals[index].goal = newGoal // 直接修改原有实例的@Published属性
    }
}

因为goal是@Published属性,修改时会自动触发GoalWrapper的objectWillChange信号,你的GoalView已经声明了@ObservedObject var goalWrapper: GoalWrapper,会自动接收信号刷新,不需要修改其他业务代码。


方案2:调整ForEach的视图刷新判定逻辑

如果你不想修改原有数据更新逻辑,就需要让SwiftUI知道即使id相同,元素内容也发生了变化,需要重新初始化GoalView。最简单的实现是给GoalView添加id修饰符,绑定会变化的业务属性:

// 修改ContentView里的ForEach部分
ForEach(manager.goals, id: \.id) { goal in
    let _ = print("goal in foreach: \(goal.goal.completitionCount) + title: \(goal.goal.title)")
    GoalView(goalWrapper:goal)
        .id("\(goal.id)_\(goal.goal.completitionCount)_\(goal.goal.dailyNotificationCount)") // 只要绑定的属性变化,就会重建视图
}.listRowBackground(Color.clear)

只要拼接的id值发生变化,SwiftUI就会销毁旧的GoalView实例,用新的goalWrapper参数创建新的实例,自然就能拿到最新数据。


方案3:使用Binding传递数据(可选替代方案)

你提到的Binding方案也是可行的,你可以把GoalWrapper的goal属性作为Binding传递给子视图,而不是直接传递整个GoalWrapper实例,这样父视图刷新时Binding会自动更新:

// 修改GoalView的声明
struct GoalView: View {
    @Binding var goal: Goal
    // 其余代码不变,把所有goalWrapper.goal替换成goal即可
}

// 调用时传递Binding
ForEach($manager.goals) { $goal in
    GoalView(goal: $goal.goal)
}

这种方案不需要依赖ObservableObject的监听,完全靠SwiftUI的状态传递机制更新,适合不需要在子视图里操作整个GoalWrapper的场景。


内容的提问来源于stack exchange,提问作者beowulf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.09 10:06:03