swiftuifirebase-authenticationenvironmentobject

"No ObservableObject of type found." (But I have included environmentObject already?)


So, I'm getting the following error:

SwiftUI/EnvironmentObject.swift:70: Fatal error: No ObservableObject of type AppViewModel found. A View.environmentObject(_:) for AppViewModel may be missing as an ancestor of this view.

However, I do actually in fact have .environmentObject(AppViewModel()) on every preview and I'm not sure why.

Here's the code in question:

import SwiftUI

struct SignUpView: View {
    
    @State var email = ""
    @State var password = ""
    @EnvironmentObject var model:AppViewModel
    
    var body: some View {
        ZStack {
            Color.theme.blue
            
            RoundedRectangle(cornerRadius: 30, style: .continuous)
                .foregroundStyle(LinearGradient(colors: [.orange, .red], startPoint: .topLeading, endPoint: .bottomTrailing))
                .frame(width: 1000, height: 475)
                .rotationEffect(.degrees(15))
                .offset(x: 20)
            
            VStack(spacing: 20) {
                
                Image("logo")
                    .resizable()
                    .scaledToFill()
                    .frame(width: 100)
                    .offset(y: 10)
                
                Text("Welcome")
                    .foregroundColor(.white)
                    .font(Font.custom("Poppins-Bold", size: 44))
                
                Text("Please Sign Up")
                    .foregroundColor(Color.theme.blue)
                    .font(Font.custom("Poppins-Regular", size: 22))
                    .offset(y:-20)
                
                // Email TextField
                TextField("", text: $email)
                    .disableAutocorrection(true)
                    .autocapitalization(.none)
                    .foregroundColor(.white)
                    .textFieldStyle(.plain)
                    .placeholder(when: email.isEmpty) {
                        Text("Email Address")
                            .foregroundColor(.white)
                            .font(Font.custom("Poppins-Light", size: 20))
                    }
                
                // Email TextBox
                Rectangle()
                    .frame(width:350, height: 1)
                    .foregroundColor(.white)
                    .padding(.top, -5)
                
                // Password TextField
                SecureField("", text: $password)
                    .disableAutocorrection(true)
                    .autocapitalization(.none)
                    .foregroundColor(.white)
                    .textFieldStyle(.plain)
                    .placeholder(when: password.isEmpty) {
                        Text("Password")
                            .foregroundColor(.white)
                            .font(Font.custom("Poppins-Light", size: 20))
                    }
                
                // Password TextBox
                Rectangle()
                    .frame(width:350, height: 1)
                    .foregroundColor(.white)
                    .padding(.top, -5)
                
                Button {
                    guard !email.isEmpty, !password.isEmpty else {
                        return
                    }
                    
                    model.signUp(email: email, password: password)
                } label: {
                    Text("Sign Up")
                        .frame(width: 200, height: 40)
                        .background(
                            Color.theme.blue
//                            RoundedRectangle(cornerRadius: 10, style: .continuous)
//                                .fill(.linearGradient(colors: [.red, .orange], startPoint: .topTrailing, endPoint: .bottomTrailing))
                            )
                        .cornerRadius(10)
                        .foregroundColor(.white)
                        .font(Font.custom("Poppins-Medium", size: 18))
                }
                
                Spacer()
                // Login Link
                HStack {
                    Text("Already Have An Account?")
                        .foregroundColor(.white)
                        .font(Font.custom("Poppins-Medium", size: 18))
                    NavigationLink("Login", destination: SignInView())
                        .foregroundColor(.orange)
                        .font(Font.custom("Poppins-Medium", size: 18))
                }.offset(y: 100)
            }
            .frame(width: 350, height: 60)
        }.ignoresSafeArea()
    }
}

struct SignUpView_Previews: PreviewProvider {
    static var previews: some View {
        SignUpView().environmentObject(AppViewModel())
    }
}

Here's my AppViewModel:


import Foundation
import Firebase


class AppViewModel: ObservableObject {
    
    let auth = Auth.auth()
    @Published var signedIn = false
    
    var isSignedIn: Bool {
        // If it does NOT equal nil, then this means it is TRUE that, YES, we are indeed signed in. Yay!
        return auth.currentUser != nil
    }
    
    
    // If you want to pass information, you have to make placeholders for the variables to be passed in.
    func signUp(email: String, password: String) {
        auth.createUser(withEmail: email, password: password) { [weak self] result, error in
            guard result != nil, error == nil else {
                return
            }
            DispatchQueue.main.async {
                // Successfully signed up
                self?.signedIn = true
            }
        }
    }
    
    func login(email: String, password: String) {
        auth.signIn(withEmail: email, password: password) { [weak self] result, error in
            guard result != nil, error == nil else {
                return
            }
            
            DispatchQueue.main.async {
                // Successfully signed in
                self?.signedIn = true
            }
//            if error != nil {
//                print(error!.localizedDescription)
//            }
        }
    }
    
    func signOut() {
        try? auth.signOut()
        self.signedIn = false
        
    }
    
}

Please let me know if I need to include more code...? Thanks in advance! (I'm a newbie.)


Solution

  • Figured it out for anyone interested...

    NavigationLink("Login", destination: SignInView())

    Needed to be changed to: NavigationLink("Sign Up", destination: SignUpView().environmentObject(self.model))