Home > OS >  Problems with SwiftUI not redrawing views
Problems with SwiftUI not redrawing views

Time:07-09

Working on my first SwiftUI project, and as I started moving some of my more complex views into their own view structs I started getting problems with the views not being redrawn.

As an example, I have the following superview:

struct ContainerView: View {

    @State var myDataObject: MyDataObject?
    
    var body: some View {
        if let myDataObject = myDataObject {
            TheSmallerView(myDataObject: myDataObject)
                .padding(.vertical, 10)
                .frame(idealHeight: 10)
                .padding(.horizontal, 8)
                .onAppear {
                    findRandomData()
                }
        }
        else {
            Text("No random data found!")
                .onAppear {
                    findRandomData()
                }
        }
        
    }

    private func findRandomData() {
        myDataObject = DataManager.shared.randomData
    }
}

Now when this first gets drawn I get the Text view on screen as the myDataObject var is nil, but the .onAppear from that gets called, and myDataStruct gets set with an actual struct. I've added breakpoints in the body variable, and I see that when this happens it gets called again and it goes into the first if clause and fetches the "TheSmallerView" view, but nothing gets redrawn on screen. It still shows the Text view from before.

What am I missing here?

EDIT: Here's the relevant parts of TheSmallerView:

struct TheSmallerView: View {

    @ObservedObject var myDataObject: MyDataObject

EDIT2: Fixed the code to better reflect my actual code.

CodePudding user response:

Try declaring @Binding var myDataStruct: MyDataStruct inside the TheSmallerView view and pass it like this: TheSmallerView(myDataStruct: $myDataStruct) from ContainerView

CodePudding user response:

You are using @ObservedObject in the subview, but that property wrapper is only for classes (and your data is a struct).

You can use @State instead (b/c the data is a struct).

Edit: The data isn't a struct. Because it is a class, you should use @StateObject instead of @State.

CodePudding user response:

In lack of complete code I created this simple example based on OPs code, which works fine the way it is expected to. So the problem seems to be somewhere else.

class MyDataObject: ObservableObject {
    @Published var number: Int
    
    init() {
        number = Int.random(in: 0...1000)
    }
}


struct ContentView: View {

    @State var myDataObject: MyDataObject?
    
    var body: some View {
        if let myDataObject = myDataObject {
            TheSmallerView(myDataObject: myDataObject)
                .onAppear {
                    findRandomData()
                }
        }
        else {
            Text("No random data found!")
                .onAppear {
                    findRandomData()
                }
        }
    }

    private func findRandomData() {
        DispatchQueue.main.asyncAfter(deadline: .now()   1) {
            myDataObject = MyDataObject()
        }
    }
}

struct TheSmallerView: View {

    @ObservedObject var myDataObject: MyDataObject
    
    var body: some View {
        Text("The number is: \(myDataObject.number)")
    }
}

  • Related