You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

SwiftUI跨页面更新Binding后List行未刷新问题求助

问题分析与解决方案

这个问题的核心在于你的Object类没有实现SwiftUI的可观察对象协议,导致属性变化无法被SwiftUI的视图系统追踪,再加上ThirdView里的更新逻辑有点多余,才出现了这种局部更新、列表不刷新的奇怪现象。咱们一步步来拆解:

1. 根本原因:Object不是可观察对象

你的Object继承自NSObject,但没有让它成为SwiftUI能感知变化的类型。SwiftUI要自动刷新视图,需要知道数据什么时候变——要么用值类型(比如struct),要么让引用类型遵循可观察协议:

  • 如果你用的是watchOS 10+/iOS 17+,可以用@Observable宏;
  • 旧版本则用ObservableObject协议+@Published属性包装器。

另外,你在ThirdViewupdate方法里做了没必要的操作:创建一个newObj副本再赋值给self.object,这不仅多余,还因为原对象的变化没被追踪,导致视图不刷新。

2. 修复步骤

步骤1:让Object成为可观察对象

方式一(watchOS 10+/iOS 17+ 推荐):用@Observable

Object类改成这样:

import Observation

@Observable
class Object: NSObject {
    var title: String
    init(title: String) {
        self.title = title
    }
}

注意:需要导入Observation框架。

方式二(旧版本兼容):用ObservableObject+@Published

import Combine

class Object: NSObject, ObservableObject {
    @Published var title: String
    init(title: String) {
        self.title = title
    }
}

步骤2:简化ThirdView的更新逻辑

不需要创建新对象,直接修改绑定对象的title即可,因为现在title的变化会被SwiftUI追踪:

struct ThirdView: View {
    @Binding var object: Object
    
    var body: some View {
        VStack {
            Text(object.title)
            Button(action: update, label: {
                Text("Tap here")
            })
        }
    }
    
    func update() {
        // 直接修改属性即可,无需创建新对象
        object.title = "Hello, World!"
    }
}

步骤3:验证ContentView的数组赋值

你提到直接初始化objects数组时能正常工作,这是因为初始赋值触发了@State的变化,强制刷新了视图,但这只是巧合——本质上Object还是不可观察的,后续的属性变化依然不会触发刷新。现在修复了Object的可观察性后,不管是在onAppear里赋值还是直接初始化,都能正常工作了。

3. 为什么之前的表现不一致?

  • 直接初始化objects时,@State的初始值设置会触发视图的初始渲染,当你修改title后,虽然Object不可观察,但可能因为某些视图层级的刷新(比如关闭sheet时的父视图刷新),刚好让第二页显示了新值,但列表页因为没有感知到Object内部的变化,所以还是旧值。
  • onAppear里赋值时,@State的变化是在视图出现后发生的,后续Object的属性变化完全没被追踪,所以第三页的Text不会实时更新,只有回到第二页时可能因为父视图的刷新才显示新值,列表页依然无感知。

这样修改后,点击第三页的按钮,你会看到第三页的Text立即更新,关闭sheet回到第二页、再回到列表页,所有地方的内容都会同步显示"Hello, World!"了。

内容的提问来源于stack exchange,提问作者Tom de Ruiter

火山引擎 最新活动