Data not being passed from View into ViewModel in Swift

I’m new to iOS development. I am learning about MVVM. I am trying to hook up my app to firebase for authentication. It seems like everything is working because it’s all building. BUT I force unwrapped the localized description error after I checked to see if it’s not nil, and I do infact have an error message of "Password must be 6 characters or more." and the test password I’m setting up is more than 6 characters, so I think the problem is that the information is not being captured from the MainView to the Viewmodel…?

Please look at my code and let me know.

I currently have 3 files:
SplashScreenView

import SwiftUI

struct SplashScreenView: View {
    @State private var isActive = false
    @State private var size = 0.7
    @State private var opacity = 0.5
    
    var body: some View {
        
        if isActive {
            withAnimation{
                MainView().environmentObject(AuthViewModel())
            }
        } else {
            ZStack {
                RoundedRectangle(cornerRadius: 30, style: .continuous)
                    .foregroundStyle(LinearGradient(colors: [.orange, .red], startPoint: .topLeading, endPoint: .bottomTrailing))
                
                
                    .ignoresSafeArea()
                VStack {
                    VStack{
                        Image("logo")
                            .resizable()
                            .scaledToFit()
                            .frame(width: 250)
                    }
                    .scaleEffect(size)
                    .opacity(opacity)
                    .onAppear(){
                        withAnimation(.easeIn(duration: 1.2)) {
                            self.size = 0.9
                            self.opacity = 1.0
                        }
                    }
                }.onAppear() {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) {
                        self.isActive = true
                    }
                }
            }
        }
    }
}

struct SplashView_Previews: PreviewProvider {
    static var previews: some View {
        SplashScreenView()
    }
}

MainView:

import SwiftUI
import Firebase

struct MainView: View {
    
    @State var email = ""
    @State var password = ""
    @EnvironmentObject var authModel:AuthViewModel
    
    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: 450)
                .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: 40))
                    .offset(y:-10)
                
                // Email TextField
                TextField("", text: $email)
                    .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)
                    .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 {
                    authModel.register()
                } label: {
                    Text("Sign Up")
                        .frame(width: 200, height: 40)
                        .background(
                            .orange
//                            RoundedRectangle(cornerRadius: 10, style: .continuous)
//                                .fill(.linearGradient(colors: [.red, .orange], startPoint: .topTrailing, endPoint: .bottomTrailing))
                            )
                        .cornerRadius(10)
                        .foregroundColor(.black)
                        .font(Font.custom("Poppins-Medium", size: 18))
                }
                
                Spacer()
                Spacer()
                // Login Link
                HStack {
                    Text("Already Have An Account?")
                        .foregroundColor(.white)
                        .font(Font.custom("Poppins-Medium", size: 18))
                    Button {
                        authModel.login()
                    } label: {
                        Text("Login")
                            .foregroundColor(.orange)
                            .font(Font.custom("Poppins-Medium", size: 18))
                    }
                }.offset(y: 100)
                
                
                    
            }
            .frame(width: 350, height: 60)
        }.ignoresSafeArea()
    }
}

struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView().environmentObject(AuthViewModel())
    }
}

extension View {
    func placeholder<Content: View>(
        when shouldShow: Bool,
        alignment: Alignment = .leading,
        @ViewBuilder placeholder: () -> Content) -> some View {

        ZStack(alignment: alignment) {
            placeholder().opacity(shouldShow ? 1 : 0)
            self
        }
    }
}

and AuthViewModel:

import Foundation
import Firebase


class AuthViewModel: ObservableObject {
    
    
    func register() {
        Auth.auth().createUser(withEmail: MainView().email, password: MainView().password) { result, error in
            if error != nil {
                print(error!.localizedDescription)
            }
        }
    }
    
    func login() {
        Auth.auth().signIn(withEmail: MainView().email, password: MainView().password) { result, error in
            if error != nil {
                print(error!.localizedDescription)
            }
        }
    }
    
    
    
}

and for ‘auth view model’ before, I had had a @published var mainView = MainView() but I don’t think that’s right…if someone can please explain what I’m doing wrong, I’d REALLY appreciate it!!! I did search on here, but the other similar questions to mine was in C# or another language.

>Solution :

Every time you call MainView() you are creating a different instance, of the view, one does not know about the other.

class AuthViewModel: ObservableObject {
    func register(email: String, password: String)  {
        Auth.auth().createUser(withEmail: email, password: password) { result, error in
            if error != nil {
                print(error!.localizedDescription)
            }
        }
    }
    
    func login(email: String, password: String) {
        Auth.auth().signIn(withEmail: email, password: password) { result, error in
            if error != nil {
                print(error!.localizedDescription)
            }
        }
    }
}

Then use

authModel.register(email: email, password: password)

authModel.login(email: email, password: password)

Try the Apple SwiftUI Tutorials, if you don’t focus on the basics you will face an uphill battle.

Leave a Reply