PreviewProvider Environment Variable Problems

Good evening,

I have a beginner question.

Namely, I have a problem with the preview provider and I do not know how to deal with them. It is helpful, no question, but I don't know how to handle it elegantly. Example:

I use an environment object in my views. When I compile the app everything works. The data is displayed compliantly.

However, the preview is no longer displayed. There comes the message

"Preview is missing environment object xxx". How could I work around this problem?

I have googled a lot, but not really found anything. In all the examples I have, the PreviewProvider is not used anywhere :) But I guess I'm doing something wrong in general

Hi :slight_smile:

Xcode/Framework specific questions are generally better asked on the Apple Developer Forums, this is a place for questions about the Swift programming language itself.

I think this should work:

struct RootView_Previews: PreviewProvider {
    static var previews: some View {
        RootView().environmentObject(ViewModel())
    }
}

I don't use SwiftUI that much currently so I could be wrong.

1 Like

TeamPuzel has one right answer. You will either need to re-architect to avoid that dependency on the environment object (described in the next paragraph) or mock the object and include it in the environment for the preview provider as shown by TeamPuzel. It is generally a good idea to design environment objects to be easy to mock. Such as swapping in a in-memory database if it represents an on-disk database.

The right answer really depends on the situation. You generally want to avoid dependencies on a environment object for reusable views (prefer bindings or other initializer parameters instead) or at the very least use environment keys instead of environment objects. They are environment objects more powerful cousin. Environment keys work better when creating custom modifiers (which you will likely do as you get more skilled with SwiftUI), they support default values, and you can override them at various points in your view hierarchy. Environment objects are generally used to help thread your state through non-reusable views (generally top-level stuff), although many devs prefer to use environment keys in all cases despite a little more boilerplate. The main advantage of environment objects is less boilerplate.

Although not your question, you are bound to run in to this too- Stuff you are doing to initialize your app also tends to break previews. You can use this package to check if you are running the app in SwiftUI preview mode in order to simplify your app startup.

Another option is to use a Framework for your previews since Xcode doesn’t need to run your app to show those previews. It just uses the dynamic linker to start the framework directly. Frameworks embedded in apps feel pretty old fashioned to me, so I usually don’t take this route.

2 Likes

Thank you for the detailed answer.

I am currently looking at how I can best implement something.

Basically the database entries should be stored in an environment object after logging in.

The idea is that then just settings can be made by the user, whatever that is and this environment object is then always updated and I then always read this environment object when saving and write to the database.

But even as I write these lines, I guess it is better to save changes made by the user punctually immediately in the database...

Even if you are using a different database, you might want to look at Core Data examples for inspiration. A handle to the database might be stored in an environment object, but any model objects should generally be passed a different way. This might be a bit complex to generalize since databases often have threading requirements that restrict how things can be passed around.