Recommand · June 14, 2021 0

Trying to fetch data from firestore coming up as nil with Swiftui

I’ve setup my Firebase Authentication within my app to register users and save their sign-up information which works perfectly. However when I try to fetch the data to populate their profile screen (with their names, profile pic, etc.), the app crashes saying it unwrapped an optional value with came up as nil. I did a print function that shows whether or not the information is actually being pulled from firestore and it is. I’m not sure why everytime I try to load my profile screen it crashes. Is there something i’m doing wrong or is there a problem with Auth?

User Model Code:

import SwiftUI
import Foundation

struct User: Encodable, Decodable{

var uuid: String
var email: String
var profileImageUrl: String
var firstname: String
var lastname: String 
}

Auth Service

import Foundation
import Firebase
import FirebaseAuth
import FirebaseStorage
import FirebaseFirestore


class AuthService {

static var storeRoot = Firestore.firestore()

static func getUserId(userid: String) -> DocumentReference {
    return storeRoot.collection("users").document(userid)
}

static func signUp(firstname: String, lastname:String, email: String, password: String, imageData: Data, onSuccess: @escaping (_ user: User) -> Void, onError: @escaping(_ errorMessage: String) -> Void) {
    
    Auth.auth().createUser(withEmail: email, password: password) {
        (authData, error) in
        
        if error != nil {
            onError(error!.localizedDescription)
            return
        }
        guard let userId = authData?.user.uid else {return}
        
        let storageProfileUserId = StorageService.storageProfileId(userId: userId)
        
        let metadata = StorageMetadata()
        metadata.contentType = "image/jpg"
        
        StorageService.saveProfileImage(userId: userId, firstname: firstname, lastname: lastname, email: email, imageData: imageData, metaData: metadata, storageProfileImageRef: storageProfileUserId, onSuccess: onSuccess, onError: onError)
    }
}


static func signIn(email: String, password: String, onSuccess: @escaping (_ user: User) -> Void, onError:
                    @escaping(_ errorMessage: String) -> Void) {
    
    Auth.auth().signIn(withEmail: email, password: password){
        (authData, error) in
        
        if error != nil {
            onError(error!.localizedDescription)
            return
        }
        
        guard let userId = authData?.user.uid else {return}
        
        let firestoreUserId = getUserId(userid: userId)
        
        firestoreUserId.getDocument{
            
            (document, error) in
           if let dict = document?.data() {
                guard let decodedUser = try? User.init(fromDictionary: dict) else {return}
            
            onSuccess(decodedUser)
            }
        }
    }
}

}

SessionStore:

class SessionStore: ObservableObject {

private var db = Firestore.firestore()


var didChange = PassthroughSubject<SessionStore, Never>()
@Published var session: User? {didSet{self.didChange.send(self)}}

var handle: AuthStateDidChangeListenerHandle?

func listen(){
    handle = Auth.auth().addStateDidChangeListener({
        (auth, user) in
        
        if let user = user{
            
            let firestoreUserId = AuthService.getUserId(userid: user.uid)
            firestoreUserId.getDocument{
                (document, error) in
                if let dict = document?.data(){

                    guard let decodedUser = try? User.init(fromDictionary: dict) else {return}
                    let dataDescription = document?.data().map(String.init(describing:)) ?? "nil"
                    print("Document data: \(dataDescription)")
                    self.session = decodedUser
                }

            }
           
        }
        else {
            print("User not found")
            self.session = nil
        }
    })
    
}

func logout() {
    do{
        try Auth.auth().signOut()
    }
    catch {
        
    }
}
func unbind() {
    if let handle = handle{
        Auth.auth().removeStateDidChangeListener(handle)
    }
}

deinit {
    unbind()
}


}

This is line of code that returns the error on my profile screen when I try to unwrap the value:

 VStack (alignment: .leading){
                    HStack {
                        Text(user!.firstname)
                            .font(.system(size: 20, weight: .bold, design: .default))
                            .foregroundColor(Color.white)
                            .multilineTextAlignment(.leading)
                        
                        Text(user!.lastname)
                            .font(.system(size: 20, weight: .bold, design: .default))
                            .foregroundColor(Color.white)
                            .multilineTextAlignment(.leading)
                    }
                    
                    Text("Edit Profile")
                        .font(.system(size: 18, weight: .regular, design: .default))
                        .fontWeight(.medium)
                        .foregroundColor(Color(#colorLiteral(red: 1, green: 1, blue: 1, alpha: 1)))
                        .multilineTextAlignment(.leading)
                    
                }
                Spacer()