SwiftUI: Trouble creating a simple boolean that every other view can see

232 views Asked by At

I’m loading data that appears throughout my app from a content management system's API. Once the data has finished loading, I’d like to be able to change a boolean from false to true, then make that boolean readable by every other view in my app so that I can create conditional if/else statements depending on whether the data has loaded yet or not.

I’ve tried doing this by creating an Observable Object at the root level to store the boolean, setting it to false by default:

@main
struct MyApp: App {
    
    @StateObject var dataLoadingObject = DataHasLoaded()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(dataLoadingObject)
        }
    }
}

class DataHasLoaded: ObservableObject {
    @Published var status: Bool = false
}

Then, in my data model file, I've tried to reference that Observable Object using @EnvironmentObject and then switch the boolean to true once the data has loaded:

class DataStore: ObservableObject {

    @Published var stories: [Story] = storyData
    
    @EnvironmentObject var dataLoadingObject: DataHasLoaded

    init() {

    // Fetching and appending
    // the data here

    self.dataLoadingObject.status = true
  }
}

The app builds successfully, but when the data loads it crashes and I get this error message: Thread 1: Fatal error: No ObservableObject of type DataHasLoaded found. A View.environmentObject(_:) for DataHasLoaded may be missing as an ancestor of this view.

It seems like the issue is that my data model view isn't explicitly a child of ContentView(), so it's not aware of the Environment Object. That's where I get stuck. Do I:

a) Try to get my data model to be a child of ContentView()?

b) Use something that doesn't require a parent/child relationship?

c) Solve this some totally different way?

d) Continue to bang my head against my desk?

Thanks for your help!

1

There are 1 answers

0
pawello2222 On

@EnvironmentObject can be used in View only. It can't be used in ObservableObject.


You can pass DataHasLoaded in init instead:

class DataStore: ObservableObject {

    @Published var stories: [Story] = storyData
    
    var dataLoadingObject: DataHasLoaded

    init(dataLoadingObject: DataHasLoaded) {
        self.dataLoadingObject = dataLoadingObject
        ...
  }
}

Just make sure you always pass the same instance.