I followed this tutorial to add Firebase user authentication to my SwiftUI project. When the user signs in or signs up, the sign in view is supposed to dissapear, and text displaying "Login Successful" should appear instead. However, this does not happen. It seems like the login / sign up process works, but the views don't change, and I suspect it may a problem with the EnvironmentalObject
. Does anybody have some ideas about why this is happening? Thank you!
Here is some of my code -
AppDelegate.swift
...
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(SessionStore()))
self.window = window
window.makeKeyAndVisible()
}
}
...
ContentView.swift
import SwiftUI
struct ContentView : View {
@EnvironmentObject var session: SessionStore
func getUser () {
session.listen()
}
var body: some View {
VStack {
if (session.session == nil) {
SignInView()
} else {
Text("Login successful!")
}
}.onAppear {
self.getUser()
}
}
}
SignInView.swift
import SwiftUI
struct SignInView : View {
@State var email: String = ""
@State var password: String = ""
@State var loading = false
@State var error = false
@State var signInWorked = ""
@EnvironmentObject var session: SessionStore
func signIn () {
loading = true
error = false
session.signIn(email: email, password: password) { (result, error) in
self.loading = false
if error != nil {
self.error = true
} else {
self.email = ""
self.password = ""
self.signInWorked = "Signed In!"
}
}
}
func signUp () {
loading = true
error = false
session.signUp(email: email, password: password) { (result, error) in
self.loading = false
if error != nil {
self.error = true
} else {
self.email = ""
self.password = ""
self.signInWorked = "Signed In!"
}
}
}
var body: some View {
VStack {
TextField("Email Adress", text: $email)
SecureField("Password", text: $password)
if (error) {
Text("ahhh crap")
}
Button(action: signIn) {
Text("Sign in")
}
Button(action: signUp) {
Text("Sign Up")
}
Text(signInWorked)
}
}
}
SessionStore.swift
import SwiftUI
import Firebase
import Combine
class SessionStore : ObservableObject {
var didChange = PassthroughSubject<SessionStore, Never>()
var session: User? { didSet { self.didChange.send(self) }}
var handle: AuthStateDidChangeListenerHandle?
func listen () {
// monitor authentication changes using firebase
handle = Auth.auth().addStateDidChangeListener { (auth, user) in
if let user = user {
// if we have a user, create a new user model
print("Got user: \(user)")
self.session = User(
uid: user.uid,
displayName: user.displayName,
email: user.email)
} else {
// if we don't have a user, set our session to nil
self.session = nil
}
}
}
func signUp(
email: String,
password: String,
handler: @escaping AuthDataResultCallback
) {
Auth.auth().createUser(withEmail: email, password: password, completion: handler)
}
func signIn(
email: String,
password: String,
handler: @escaping AuthDataResultCallback
) {
Auth.auth().signIn(withEmail: email, password: password, completion: handler)
}
func signOut () -> Bool {
do {
try Auth.auth().signOut()
self.session = nil
return true
} catch {
return false
}
}
func unbind () {
if let handle = handle {
Auth.auth().removeStateDidChangeListener(handle)
}
}
}
User.swift
import Foundation
class User {
var uid: String
var email: String?
var displayName: String?
init(uid: String, displayName: String?, email: String?) {
self.uid = uid
self.email = email
self.displayName = displayName
}
}
You need to add the property wrapper @Published
to your var session
in SessionStore ensure that all views using it are refreshed when it changes. So change
var session: User? { didSet { self.didChange.send(self) }}
to
@Published
var session: User? { didSet { self.didChange.send(self) }}
See here for more info: https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With