skip to Main Content

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.

3

Answers


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

    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
  3. 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)")
        }
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search