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
相关产品推荐
相关产品推荐

