我正在使用Firebase构建一个应用程序,其初始版本为SignInViewController
,用于加载登录页面,供用户通过电子邮件进行身份验证,从而触发以下方法:
@IBAction func didTapSignIn(sender: AnyObject) {
let email = emailField.text
let password = passwordField.text
FIRAuth.auth()?.signInWithEmail(email!, password: password!) { (user, error) in
if let error = error {
print(error.localizedDescription)
return
}
self.signedIn(user!)
}
}
func signedIn(user: FIRUser?) {
AppState.sharedInstance.displayName = user?.displayName ?? user?.email
AppState.sharedInstance.signedIn = true
NSNotificationCenter.defaultCenter().postNotificationName(Constants.NotificationKeys.SignedIn, object: nil, userInfo: nil)
performSegueWithIdentifier(Constants.Segues.SignInToHome, sender: nil)
}
SignInViewController
还会在应用启动时检查是否有缓存的当前用户,如果是,则在用户身上签名:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
//Synchronously gets the cached current user, or null if there is none.
if let user = FirebaseConfigManager.sharedInstance.currentUser {
self.signedIn(user)
}
}
用户登录后,应用会转到HomeScreenViewController
,显示"退出"导航栏左上角的按钮。当用户点击"退出"按钮,该用户应该退出,应用程序应该使用以下方法转回SignInViewController
:
@IBAction func didTapSignOut(sender: UIBarButtonItem) {
print("sign out button tapped")
let firebaseAuth = FIRAuth.auth()
do {
try firebaseAuth?.signOut()
AppState.sharedInstance.signedIn = false
dismissViewControllerAnimated(true, completion: nil)
} catch let signOutError as NSError {
print ("Error signing out: \(signOutError)")
} catch {
print("Unknown error.")
}
}
当我点击"退出"按钮,调用didTapSignOut
方法并执行。
但是,在执行try firebaseAuth?.signOut()
代码行之后,当前用户应为nil
。但是当我在Xcode控制台中打印出当前用户时,当前用户仍然登录:
po FIRAuth.auth()?.currentUser
▿ Optional<FIRUser>
- Some : <FIRUser: 0x7fde43540f50>
由于当前用户在firebaseAuth?.signOut()
被调用后没有注销,一旦应用程序回到SignInViewController
,应用程序仍然认为有一个缓存的当前用户,以便用户获得再次登录。
这可能是钥匙串问题吗?
是否与NSNotificationCenter.defaultCenter().postNotificationName
被调用有关?
我的代码直接来自Google Firebase Swift Codelab,所以我不确定它为什么不能正常工作: https://codelabs.developers.google.com/codelabs/firebase-ios-swift/#4
答案 0 :(得分:5)
您可以在视图控制器的viewDidAppear
方法中添加一个侦听器,如下所示:
FIRAuth.auth()?.addStateDidChangeListener { auth, user in
if let user = user {
print("User is signed in.")
} else {
print("User is signed out.")
}
}
这允许您在用户的身份验证状态发生更改时执行代码。它允许您监听事件,因为Firebase中的signOut
方法没有完成处理程序。
答案 1 :(得分:2)
使用感叹号而不是问号。
try! FIRAuth.auth()!.signOut()
答案 2 :(得分:2)
GIDSignIn.sharedInstance().signOut()
答案 3 :(得分:1)
我实际上也有这个问题。我还使用Firebase提供的方法登出用户(就像你一样),但是当我打印到控制台时,它说我还有一个可选用户。
我必须更改设置当前用户的逻辑,以便始终由Firebase提供的身份验证处理程序进行配置:
var currentUser: User? = Auth.auth().currentUser
var handle: AuthStateDidChangeListenerHandle!
init() {
handle = Auth.auth().addStateDidChangeListener { (auth, user) in
self.currentUser = user
if user == nil {
UserDefaults.standard.setValue(false, forKey: UserDefaults.loggedIn)
} else {
UserDefaults.standard.setValue(true, forKey: UserDefaults.loggedIn)
}
}
}
只要您从此句柄引用当前用户,无论身份验证状态如何,它都将更新当前用户。
答案 4 :(得分:0)
我刚刚遇到了同样的问题 - Firebase + Swift 3在注销时不会触发stateDidChangeListeners
,这让我的应用程序认为用户仍然登录。
最终为我工作的是保存并重用对FIRAuth.auth()
实例的单个引用,而不是每次都调用FIRAuth.auth()。
调用FIRAuth.auth()?.signOut()
不会触发我之前附加的stateDidChangeListeners
。但是当我保存变量并在两种方法中重复使用它时,它按预期工作。
答案 5 :(得分:0)
当firebase注销方法可能引发错误时,某些答案正在使用强制解包。不要这样做!
相反,调用应该在do-catch-block中完成,如下所示
for (i in 1:length(df$region)){
if (nchar(df$region[i])==4) {
df$region[i] <- paste0("0", df$region[i])
}
}
然后,您可以使用Auth.auth()。addStateDidChangeListener来监听状态更改并相应地处理。