SwiftUI - Firebase身份验证 - 环境对象在登录后不更新

6
我按照此教程添加了Firebase用户身份验证到我的SwiftUI项目中。当用户登录或注册时,登录视图应该消失,而显示“登录成功”的文本。然而,这并没有发生。似乎登录/注册过程是有效的,但视图没有改变,我怀疑可能是EnvironmentalObject的问题。有人对为什么会发生这种情况有一些想法吗?谢谢!

以下是我的一些代码 -

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
}
}

1
我也有同样的问题。应用程序在模拟器和设备上运行正常,但在画布中却无法正常工作。 - Giuseppe Sapienza
在我的情况下,这种情况发生在所有三个方面。登录成功,但视图没有消失。 - George B
是的,对我来说也是一样。标志正常工作,但视图在画布中不会消失(模拟器和设备可以正常工作)。 - Giuseppe Sapienza
pod 'CombineFirebase/Auth' 将大大简化此操作。 - kumar shivang
4个回答

5

0
你可以尝试这个例子iOS - swiftUI - Firebase 登录完整设置,它完美地工作并且也能够满足你的需求。在这个例子中,在展示器模态下完成登录过程,所以当登录成功后,它会回调定义的函数并关闭登录页面。希望这能对你有所帮助。

0

这是一个专门针对那些只在模拟器和设备上看到它工作,但在画布中没有看到的答案;您必须转到代码的YourView_Previews:部分(在底部),并将.environmentObject(SessionStore())添加到在预览中调用的视图中(如果您在ContentView.swift中,则应该是ContentView().environmentObject(SessionStore()) 在预览的正文中


0

好的,这对我有用:如果@Published变量不起作用,只会带您到HomeView(如果用户已登录,则指定要转到的视图),则需要添加:

    func () { 
        session.signOut()
    }

将此代码放入您的 HomeView() 中(不是 body,而是 struct),并创建一个调用此函数的 signOut 按钮 -- 问题在于,直到您将用户注销之前,他们仍然保持登录状态,而这个简单的修复方法应该可以解决这个问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接