0

I'm building an app that uses firebase to authenticate users. I'm trying to sign up a new user and keep getting a fatal error. New to Swift so I'm probably missing something obvious.

Error: Fatal error: No ObservableObject of type AuthViewModel found. A View.environmentObject(_:) for AuthViewModel may be missing as an ancestor of this view. This is focused on my sign up action button where the viewModel is referenced (see just below // end of v).

Sign Up View code:

import SwiftUI

struct SignUpView: View {
    
    @State var firstName = ""
    @State var lastName = ""
    @State var email = ""
    @State var password = ""
    @State var confirmPassword = ""
    
    @Environment(\.presentationMode) var mode
    
    
    @EnvironmentObject var viewModel: AuthViewModel
    
    var body: some View {
        
        ZStack {
            
            BackgroundGradientView()
            
            VStack {
                LogoView()
                    .padding(.bottom, 25)
            
            VStack(spacing:20) {
                
                UserTextField(text: $firstName, placeholder: "First Name")
                UserTextField(text: $lastName, placeholder: "Last Name")
                EmailTextField(text: $email)
                PasswordSecureField(text: $password, placeholder: "Password")
                PasswordSecureField(text: $confirmPassword, placeholder: "Confirm Password")
                
            } // end of V
            .padding(.horizontal, 32)
                
                Button { // sign up action
                    viewModel.register(withEmail: email, password: password, firstName: firstName, lastName: lastName)
                } label: {
                    AuthenticateButtonView(text: "Sign Up").padding()
                }
                
                Spacer()
                
                Button {
                    mode.wrappedValue.dismiss()
                } label: {
                    HStack {
                        Text("Already have an account?")
                            .font(.system(size:14))
                        Text("Sign In")
                            .font(.system(size:14, weight:.semibold))
                    }
                    .foregroundColor(.white)
                }
                .padding(.bottom,16)
            } // end of second V
        }
    }
}

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

AuthViewModel code:

import SwiftUI
import Firebase
import FirebaseAuth

class AuthViewModel: ObservableObject { 
    
    @Published var userSession: User? 
    @Published var currentUser: AppUser? 
    
    static let shared = AuthViewModel()
    
    init() {
        userSession = Auth.auth().currentUser
        //fetchUser()
    }
    
    func fetchUser() {
        guard let uid = userSession?.uid else { return } 
        COLLECTION_USERS.document(uid).getDocument {
            snapshot, _ in
            guard let user = try? snapshot?.data(as: AppUser.self) else { return }
            self.currentUser = user
        }
    } 
    
    func login(withEmail email: String, password: String) {
        
        Auth.auth().signIn(withEmail: email, password: password) { result, error in
            if let error = error {
                print("Login Failed\(error.localizedDescription)")
                return
            }
            
            guard let user = result?.user else { return }
            self.userSession = user
            self.fetchUser()
        }
    }
    
    func register(withEmail email: String, password: String, firstName: String, lastName: String) {
        Auth.auth().createUser(withEmail: email, password: password) {
            result, error in
            if let error = error {
                print("Registeration Failed \(error.localizedDescription)")
                return
            }
            
            guard let user = result?.user else { return }
            
            let data = ["uid": user.uid,
                        "firstName": firstName,
                        "lastName": lastName,
                        "email": email]
            
            COLLECTION_USERS.document(user.uid).setData(data) { _ in
                print("Succesfully uploaded data")
                self.userSession = user
                self.fetchUser()
                
            }
        }
    }
    
    func signout() {
        self.userSession = nil
        try? Auth.auth().signOut()
    }        

}

Again, probably something obvious but would benefit from an explainer.

FlexBoxer
  • 91
  • 7
  • Did you google the error? It is always the same answer – lorem ipsum Oct 11 '22 at 18:19
  • Yes, I've googled and gone through the similar questions on stack. Still having issues with the error. – FlexBoxer Oct 11 '22 at 19:11
  • So what did you try to solve this? Where do you struggle? – burnsi Oct 11 '22 at 19:35
  • I'm confused as to what the error is telling me - I've considered two possible solutions, one is placing the environment object higher up within the code and the other, creating an instance such as @Stateobject var viewModel = AuthViewModel()? – FlexBoxer Oct 11 '22 at 19:45
  • 1
    An EnvironmentObject needs a parent StateObject that is injected into the views with the appropriate modifier. The error you get is because you have not injected the value of the StateObject so the environment object can’t find the object. – lorem ipsum Oct 11 '22 at 21:24
  • 1
    have a look at this helpful info: https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app it will tell you what the other comments have told you, you need a `@StateObject var ...` higher up your view hierarchy, that you pass using `.environmentObject(...)` – workingdog support Ukraine Oct 11 '22 at 22:19

0 Answers0