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

SwiftUI修改绑定视图ObservableObject导致当前视图重初始化如何解决

问题根因

你触发Click2时PlaygroundView反复初始化的核心问题是错误创建了绑定到整个BindingView结构体的Binding参数传入PlaygroundView:

  • 当你修改BindingView持有的OBSObject的@Published属性时,BindingView会触发自身body重绘
  • 此时你在BindingView.body中传入PlaygroundView的Binding<BindingView>检测到指向的BindingView结构体发生了变更,SwiftUI就会重新初始化PlaygroundView,进而触发init里的打印逻辑
  • Click1不会触发重初始化是因为修改的是PlaygroundView自身持有的ObservedObject,只会触发PlaygroundView的body刷新,不会影响上层传入的初始化参数,自然不会触发重新初始化。

解决方法

不要绑定整个View结构体,只传递你需要操作的对象/属性即可,最优方案是直接把上层BindingView持有的OBSObject引用直接传入PlaygroundView,修改后的代码如下:

struct PlaygroundView: View{
    @ObservedObject var obs:OBSObject = OBSObject()
    // 直接持有上层传下来的OBSObject引用即可,不需要绑定整个View
    @ObservedObject var parentObs: OBSObject

    init(parentObs: OBSObject){
        self.parentObs = parentObs
        print("playground inits")
    }

    var body: some View {
        Button(action: Click2){
            Text("Click here")
        }
    }

    func Click1(){
        obs.theOnlyProperty.toggle()
    }

    func Click2(){
        parentObs.theOnlyProperty.toggle()
    }
}

//OBSObject
class OBSObject : ObservableObject{
    @Published var theOnlyProperty:Bool = false
}

//BindingView
struct BindingView : View{
    @ObservedObject var obs : OBSObject = OBSObject()

    var body: some View {
        // 直接把obs对象传入即可,不需要创建绑定到self的Binding
        PlaygroundView(parentObs: obs)
    }
}

//app入口
@main
struct ReinitApp: App {
    var body: some Scene {
        WindowGroup {
            BindingView()
        }
    }
}

修改后点击按钮触发Click2时,仅会刷新两个View的body内容,不会重新初始化PlaygroundView,因为PlaygroundView的初始化参数是OBSObject的引用,引用本身没有发生变更,只是其内部属性更新,SwiftUI不会因此重新初始化View结构体。如果确实需要绑定上层的某个属性,也仅绑定对应的属性值,不要绑定整个View结构体,这是SwiftUI开发中的常见错误写法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 17:45:06