skip to Main Content

I am starting with SwiftUI coding and making some projects, everything worked fine but then the error poped up "Cannot find viewModel in scope"
I looked in the code but in my opinion is the viewModel in scope.

Here is my code:

import FirebaseAuth

class AppViewModel: ObservableObject {
        let auth = Auth.auth()
    }
}

struct ContentView: View {
    @EnvironmentObject var viewModel: AppViewModel
    var body: some View {
        NavigationView {
            if viewModel.signedIn {
                Text("You are Signed In")
            } else {
                SignInView()
            }
        }
        .onAppear {
            viewModel.signedIn = viewModel.isSignedIn
        }
    }
}

struct SignInView: View {
    var body: some View {
        VStack {      
            Button("Sign-In"){ 
                guard !email.isEmpty, !password.isEmpty else {
                    return
                }
                **viewModel.signIn(email: email, password: password)**
            }
        }
    }
}```

3

Answers


  1. You will need to pass in the viewModel into the SignInView. This view might be shown by the ContentView which holds the viewModel, but the SignInView itself does not know what the viewModel is or where to get it from.

    On the "how":

    struct SignInView: View {
        @StateObject var viewModel: AppViewModel
        ...
    }
    

    Doing that, the view now knows it needs a parameter on its initializer. You will now get a compiler error on the place where you use the SignInView. Now just change that line to SignInView(viewModel: viewModel) and you should be good to go.

    Login or Signup to reply.
  2. Declaring the EnvironmentObject doesn’t create its instance. It just says that you have set .environmentObject somewhere above in the hierarchy and that you can use it in this view. However if you get the error you obviously haven’t set it.

    Alternatively you can use @StateObject to define viewModel available to that view, but even then it won’t be instances unless you instance it in the code or in its declaration.

    Login or Signup to reply.
  3. try this approach, where you declare a @StateObject var viewModel = AppViewModel() in your App, and pass it down to all other views:

    @main
    struct YourApp: App {
        @StateObject var viewModel = AppViewModel()  // <-- here
    
        var body: some Scene {
            WindowGroup {
                ContentView()
                    .environmentObject(viewModel)  // <-- here
            }
        }
    }
    
    class AppViewModel: ObservableObject {
            @Published var signedIn: Bool = false  // <--- here
            // ....
            let auth = Auth.auth()
            // .... 
        }
    }
    
    struct ContentView: View {
        @EnvironmentObject var viewModel: AppViewModel
    
        var body: some View {
            NavigationView {
                if viewModel.signedIn {
                    Text("You are Signed In")
                } else {
                    SignInView()
                }
            }
            .onAppear {
                // --- here, meaningless
                // viewModel.signedIn = viewModel.isSignedIn
            }
        }
    }
    
    struct SignInView: View {
        @EnvironmentObject var viewModel: AppViewModel  // <-- here
        // ....
    
        var body: some View {
            VStack {
                Button("Sign-In"){
                    guard !email.isEmpty, !password.isEmpty else {
                        return
                    }
                    viewModel.signIn(email: email, password: password)
                }
            }
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search