返回 Firebase 用户名时的 iOS 异步任务问题

Posted

技术标签:

【中文标题】返回 Firebase 用户名时的 iOS 异步任务问题【英文标题】:iOS Async Task Issue When Returning Firebase Usernames 【发布时间】:2016-07-30 22:50:15 【问题描述】:

我非常接近完成我的项目的这一部分。我学到了很多,但就是看不到,总结一下。我要做的基本上是检查电子邮件地址是否已被其他用户使用。为此,我正在使用以下代码:

func emailCheck(input : String, result:(canRegister: Bool?) -> Void)
    var canRegister : Bool?
    FIRAuth.auth()?.signInWithEmail(input, password: " ")(user, error) in
        if error != nil 
            if(error?.code == 17009)
                print("Wrong Password")
                canRegister = false
            else if(error?.code == 17011)
                print("Unknown User")
                canRegister = true
            else
                canRegister = false
            
           
       

整个Async 对我来说只有 6 个小时,所以如果您有任何建议,请告诉我。但是当一个按钮被按下时,这个函数就会被调用,只需这样做:

print(emailCheck(emailTxt.text!)(canRegister : Bool?) -> Void in)

由于某种原因,返回的是空的,而不是 truefalse 甚至 nil。它只返回() 但是当我输入正确的密码时它确实返回Wrong Password,不太确定这是否相关。有人可以帮忙吗?谢谢大家!

添加信息 经过建议,代码和对代码的引用现在看起来像这样:(仅包含重要部分)

class LoginViewController: UIViewController 
@IBAction func nextScreen(sender: UIButton) 
 emailCheck(emailTxt.text!)  isValid in
                if isValid 
                    print("Valid!")
                 else 
                    print("Invalid!")
                
            

func emailCheck(input: String, callback: (isValid: Bool) -> Void) 
    FIRAuth.auth()?.signInWithEmail(input, password: "")  (user, error) in
        var canRegister = false

        if error != nil 
            if (error?.code == 17009) 
                //wrong password error
             else if(error?.code == 17011) 
                //email doesn't exist
                canRegister = true
            
        

        callback(isValid: canRegister)
    

这背后的过程是,如果返回的代码是用户不存在,那么邮箱账号是开放的,可以被抵抗,从而允许canRegister,否则,如果传入的密码是空的不正确,那么我们知道该帐户存在,因此无法注册使用。目前,canRegister 返回的值等于此处定义的值:

var canRegister = false

返回函数调用。

【问题讨论】:

更新后的代码对我来说是正确的。由于某种原因,您似乎没有从 Firebase 收到错误代码 17011。深入研究他们的文档,我认为他们的 API 的行为与您预期的不同。根据this page,FIRAuthErrorCodeUserNotFound 错误(与您使用的 17011 代码匹配)“表示未找到用户帐户。如果用户帐户已被删除,可能会发生这种情况。”不是如果这是引发该错误的唯一情况,我很清楚...... 无论如何,要更深入地了解您正在尝试做的事情......在我看来,您可能正在尝试处理他们为您处理的事情。 createUserWithEmail 方法的 docs 表示它可能会引发 FIRAuthErrorCodeEmailAlreadyInUse 错误,这似乎就是您要自己处理的问题。为什么不尝试创建它并处理这个错误呢? @dbburgess 你知道它是什么吗?我在这一行中遗漏了一个空格:...signInWithEmail(input, password: " ") ... 因为password 没有空格,所以firebase 没有将其读取为空密码,而可能更像是nil,这样就不会引发错误。感谢您的所有帮助! 再次感谢您的精彩回答,希望其他为此苦苦挣扎的人也会投票! 【参考方案1】:

您正在打印emailCheck 的返回值,这不是您想要的。异步只是意味着这部分代码将在以后运行。考虑这个简单的函数:

func emailCheck(input: String) -> Bool 
  var valid = true

  if input.characters.count == 0 
    valid = false
  

  return valid

这只是检查电子邮件是否包含超过零个字符。它可以大大简化,但我已经让它更详细一点来说明差异。要使用它,您只需执行以下操作:

let isValid = emailCheck("me@example.com")

if isValid 
    print("Valid!")
 else 
    print("Invalid!")

如果我们希望该方法能够异步工作,我们会为其提供回调。回调只是一个函数,可以调用它让我们知道结果是什么,而不是直接由函数返回。看起来是这样的:

func emailCheck(input: String, callback: (isValid: Bool) -> Void) 
    var valid = true

    if input.characters.count == 0 
        valid = false
    

    callback(isValid: valid)


func callback(isValid: Bool) 
    if isValid 
        print("Valid!")
     else 
        print("Invalid!")
    


emailCheck("me@example.com", callback: callback)

注意emailCheck 不再返回一个值,而是实际执行带有结果的回调方法。这还不是真正的异步,因为回调会立即执行,但如果我们愿意,它可以让我们做异步的事情。

Swift 有一些简洁的语法糖,可以将回调作为最后一个参数传递,而无需像我上面那样明确声明它们。这就是您用于 Firebase 的 signInWithEmail 方法的内容。在这段代码中使用它,它看起来像这样:

emailCheck("me@example.com")  isValid in
    if isValid 
        print("Valid!")
     else 
        print("Invalid!")
    

它的作用完全相同,但我认为在这种情况下它看起来更好一些。所以现在我们有一个很好的设置可以检查电子邮件,并且一旦我们知道电子邮件是否有效,一些代码可以稍后运行。把它们放在一起:

func emailCheck(input: String, callback: (isValid: Bool) -> Void) 
    FIRAuth.auth()?.signInWithEmail(input, password: " ")  (user, error) in
        var canRegister = false

        if error != nil 
            if (error?.code == 17009) 
                print("Wrong Password")
             else if(error?.code == 17011) 
                print("Unknown User")
                canRegister = true
            
        

        callback(isValid: canRegister)
    



var availableEmail = false

emailCheck("me@example.com")  isValid in
    if isValid 
        print("Valid!")
     else 
        print("Invalid!")
    

    availableEmail = isValid
    // This prints **second**, and should print `true`, if `isValid` was true.
    print(availableEmail)


// This prints **first**, and should print `false`, because the callback likely has not run yet.
print(availableEmail)

编辑:参见上面的print 代码/cmets,它说明了当您使用回调方法时变量不会立即更新。

附加编辑:另一种结构方式,为了清楚起见使用另一个函数:

emailCheck("me@example.com")  isValid in
    if isValid 
        print("Valid!")
     else 
        print("Invalid!")
    

    self.emailCheckComplete(isValid)


func emailCheckComplete(availableEmail: Bool) 
    // This is the same as above, but perhaps helps you follow the flow.
    print(availableEmail)

【讨论】:

嗯,是的,isValidBool 类型,所以你可以使用callback(isValid: true),但是如果电子邮件被占用了怎么办?你想用假的。这就是我使用canRegister 的原因,它也是Bool 并相应地设置为true / 或false。 在我的例子中,emailCheck 没有返回 any 值,但也许我不明白你的意思。 您可以根据我的示例使用您所做的更改来编辑您的帖子吗?查看更新后的代码有助于理解您的意思。 不,availableEmail 正在更新...但您可能在在回调方法的范围之外使用它。在这种情况下,您正在使用它之前它被更新。了解何时代码的每个部分运行是至关重要的,并且在您第一次学习时很容易出错。请记住,回调仅在将来的某个时间运行。它之外的任何代码都会立即运行。由于格式限制,很难在 cmets 中演示,请参阅我的答案编辑以了解更多详细信息。 回调一个completion:块。我只是选择将其命名为callback:,但您可以将其命名为completion:。这只是语义。但只有其中的代码才能访问更新的值。您可以从该块中调用一个函数,我发现它可以帮助澄清代码的流动方式。查看其他修改。

以上是关于返回 Firebase 用户名时的 iOS 异步任务问题的主要内容,如果未能解决你的问题,请参考以下文章

只有在 SwiftUI 和 Firebase 中完成循环中的异步调用时,如何才能返回函数?

仍然在线时的 Firebase 缓存,iOS

Firebase Auth iOS用户匿名创建但未在控制台中显示

如何通过异步调用 uid 从 Firebase 查询数据

用户登录时,Firebase currentUser 在 iOS Today Extension 中返回 nil

Firebase ios sdk 异步和线程