0

I have been stuck by this wired problem for a couple of days. The code is very simple just as below:

struct PlaygroundView: View{

@ObservedObject var obs:OBSObject = OBSObject()
@Binding var bindingView:BindingView

init(bindingView:Binding<BindingView>){
    self._bindingView = bindingView
    print("playground inits")
}

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

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

func Click2(){
    bindingView.obs.theOnlyProperty.toggle()
}
}

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

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

var body: some View {
PlaygroundView(bindingView: Binding<BindingView>(
    get: { self },
    set: { _ in }
))
}
}

//the entry of the app
@main
struct ReinitApp: App {
var body: some Scene {
    WindowGroup {
        BindingView()
    }
}
}

The wired thing is that if I trigger Click1 func and toggle "theOnlyProperty" which is a bool published property in obs object, it will not cause reinitialize the PlaygroundView. However, if I trigger Click2 func, the PlaygroundView view will be reinitialized. The only difference is in Click1, the obs object is belong to the current view whereas in Click2,the obs object is belong to another view. My question is, is there any way to update obs object in the bindingView without causing the current view PlaygroundView reinitializes itself? Any help would be much appreciated!

jeep
  • 615
  • 2
  • 10
  • 19
  • Can you include the relevant code to make this compilable? – jnpdx Nov 03 '21 at 04:35
  • @jnpdx I've included the relevant code now and It's compilable. The output is exactly as I described above. – jeep Nov 03 '21 at 06:28
  • Okay -- I can compile now, but I'm struggling to see what this is actually trying to represent. Why do you have a `Binding` to a `View`? And that `View` isn't actually displayed anywhere in the hierarchy... Is this representative of some other issue where there's a use case? In general, I'd say `Click1` doesn't refresh because SwiftUI is smart enough to know that the view doesn't actually reference `theOnlyProperty` anywhere, so it doesn't need to update. `Click2` is an odd circular dependency, which is the use-case I'm wondering about. – jnpdx Nov 03 '21 at 06:33
  • @jnpdx This is a simplified example. In my original project, the BindingView is more complex. It kept some properties(can be ViewModels)I may reuse in other views. Click2 represents the situation I have to modify an observable property(ViewModel) in the BindingView. But I don't want the current view get reinitialized cause I will lost track of states of the current view. For Click1, even if I reference "theOnlyProperty" somewhere in the current view, the view still will not reinitialize – jeep Nov 03 '21 at 06:58
  • Reinitialize != lose state. That's what `@State` variables are for -- SwiftUI views often reinitialize and may not even get entered into the hierarchy -- that's one reason it can be a bad idea to keep references to them. This seems like an A/B problem. – jnpdx Nov 03 '21 at 07:00
  • @jnpdx In my experience, reinitialize will cause properties to hold the initial values, then lose state. But I'm not sure, I will make a test for it. And I am also concerned about reinitialize will cause performance issue. Especially when init func is heavy or a view periodically reinitializes by a timer. I hope there is a way to tell swiftui not to reinitialize the view unless I ask for it. – jeep Nov 03 '21 at 07:21
  • Definitely avoid *any* heavy work in SwiftUI init -- instead, it should be done in something like `onAppear`. If you're initializing view models, make sure that you're using `StateObject(wrappedValue:)` which uses an autoclosure to only go through the `ObservableObject`'s `init` phase if the view will actually be inserted in the hierarchy. You may want to watch WWDC 2021 Demystifying SwiftUI for some explanation of how `View`s are diffed and how updates can be done efficiently. – jnpdx Nov 03 '21 at 07:24
  • 1
    @jnpdx I just proved "Reinitialize != lose state" with a simple test. Everything looks more reasonable now. I will checkout that WWDC video. I really need to learn more about SwiftUI's basic mechanisms. Thank you so much for your help! – jeep Nov 03 '21 at 07:39

0 Answers0