Unwrapping values the conventional way in SwiftUI views is not allowed, but you can do so within the body
of, say, an HStack
or a VStack
. Below I am trying to unwrap a user I was certain was not nil. My LoginView
lets a user create an account on Firebase Firestore, logs you in if a user enters the correct values, and shows an alert view if not.
In my HomeView.swift
, the first screen after launch, I crash when trying to present the user image. However, when I unwrap the user, the user is still nil in the console. I think this is because Firebase doesn't have time to load the image before the view initializes. But I could be wrong. Help.
struct HomeProfileView: View {
@EnvironmentObject var session: SessionStore
@State var showDashboard = false
var user: User?
var body: some View {
if user != nil {
URLImage(URL(string: user!.profileImageUrl)!, content: {
$0.image
.resizable()
.aspectRatio(contentMode: .fill)
.clipShape(Circle())
})
.frame(width: 50, height: 50)
.background(Color(#colorLiteral(red: 0.9490196078, green: 0.9490196078, blue: 0.9490196078, alpha: 1)))
.clipShape(Circle())
.shadow(color: Color.black.opacity(0.1), radius: 1, x: 0, y: 1)
.shadow(color: Color.black.opacity(0.2), radius: 10, x: 0, y: 10)
.sheet(isPresented: $showDashboard) {
DashboardView(showDashboard: $showDashboard)
}
}
}
}
I don't think I need an optional user, here, but I do not know how to safely unwrap the user otherwise. Another version is using the session EnvironmentObject
to access the currently logged user.
struct HomeProfileView: View {
@EnvironmentObject var session: SessionStore
@State var showDashboard = false
var body: some View {
if session.isLoggedIn {
URLImage(URL(string: session.userSession!.profileImageUrl)!, content: {
$0.image
.resizable()
.aspectRatio(contentMode: .fill)
.clipShape(Circle())
})
.frame(width: 50, height: 50)
.background(Color(#colorLiteral(red: 0.9490196078, green: 0.9490196078, blue: 0.9490196078, alpha: 1)))
.clipShape(Circle())
.shadow(color: Color.black.opacity(0.1), radius: 1, x: 0, y: 1)
.shadow(color: Color.black.opacity(0.2), radius: 10, x: 0, y: 10)
.sheet(isPresented: $showDashboard) {
DashboardView(showDashboard: $showDashboard)
}
}
}
}
The session
property belongs to a SessionStore
class and is essentially an optional User
.
import Foundation
import Combine
import Firebase
class SessionStore: ObservableObject {
@Published var isLoggedIn: Bool = UserDefaults.standard.bool(forKey: "isLoggedIn") {
didSet {
UserDefaults.standard.set(self.isLoggedIn, forKey: "isLoggedIn")
}
}
var userSession: User?
var handle: AuthStateDidChangeListenerHandle?
func listenAuthenticationState() {
handle = Auth.auth().addStateDidChangeListener({ (auth, user) in
if let user = user {
print(user.email as Any)
let firestoreUserId = Ref.FIRESTORE_DOCUMENT_USERID(userId: user.uid)
firestoreUserId.getDocument { (document, error) in
if let dict = document?.data() {
guard let decodeUser = try? User.init(fromDictionary: dict) else { return }
self.userSession = decodeUser
}
}
self.isLoggedIn = true
} else {
print("User is Logged Out")
self.isLoggedIn = false
self.userSession = nil
}
})
}
}
The logged in user is indeed logged in but I cannot access any properties.
I have this working. Not sure how scalable it is but I am doing a not equals nil. I also put it in a button to toggle it versus an
onTapGesture
.