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

返回Firebase用户名时出现iOS异步任务问题,ios,swift,asynchronous,firebase-authentication,Ios,Swift,Asynchronous,Firebase Authentication,我很快就要完成我项目的这一部分了。我学到了很多,但就是看不见,总结一下。我想做的是检查一个电子邮件地址是否已经被其他用户使用。为此,我使用以下代码: func emailCheck(input : String, result:(canRegister: Bool?) -> Void){ var canRegister : Bool? FIRAuth.auth()?.signInWithEmail(input, password: " "){(user, error) in

我很快就要完成我项目的这一部分了。我学到了很多,但就是看不见,总结一下。我想做的是检查一个电子邮件地址是否已经被其他用户使用。为此,我使用以下代码:

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})
出于某种原因,这将返回空,而不是
true
false
甚至
nil
。它只返回
()
,但是当我输入正确的密码时,它确实返回了
错误的密码
,不太确定这是否相关。有人能帮忙吗?谢谢大家

添加信息 建议之后,代码和对代码的引用现在看起来如下:(仅包括重要部分)

虽然这背后的过程是,如果返回的代码是用户不存在,那么电子邮件帐户将被拒绝,从而允许
可以注册
,否则,如果传入该帐户的空密码不正确,那么我们知道该帐户存在,因此无法使用注册。当前,
canRegister
返回的值等于此处定义的值:

var canRegister = false

返回函数调用

您正在打印
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!")
}
emailCheck("me@example.com") { isValid in
    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的
通过电子邮件登录的方法。在这段代码中使用它,看起来像这样:

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

if isValid {
    print("Valid!")
} else {
    print("Invalid!")
}
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)
编辑:请参阅上面的
打印
代码/注释,这些注释说明了在使用回调方法时变量如何不会立即更新

附加编辑:另一种结构方式,为清晰起见,使用另一种功能:

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

嗯,是的,
isValid
是类型
Bool
,因此您可以执行
回调(isValid:true)
,但是如果电子邮件被接收呢?你会想用false。这就是为什么我使用了
canRegister
,这也是一个
Bool
,并相应地设置为true/或false。在我的示例中,
emailCheck
没有返回任何值,可能我不理解你的意思。你能根据我的示例用你所做的更改编辑你的帖子吗?查看更新的代码有助于理解您的意思。不,
availableEmail
正在更新…但您可能在回调方法的范围之外使用它。在这种情况下,您正在更新它之前使用它。理解代码的每一部分何时运行是一个关键问题,在您第一次学习时很容易出错。记住,回调只会在将来的某个时候运行。它之外的任何代码都会立即运行。由于格式限制,很难在注释中演示,有关更多详细信息,请参阅我的答案编辑。回调是一个
完成:
块。我只是选择将它命名为
callback:
,但您可以将它命名为
completion:
。这只是语义学。但只有其中的代码才能访问更新的值。您可以从该块中调用函数,我发现这有助于澄清代码的流动方式。请参阅其他编辑。更新的代码在我看来是正确的。似乎出于某种原因,您没有从Firebase获得错误代码17011。深入研究他们的文档,我认为他们的API并没有按照您所期望的方式运行。根据,FIRAuthErrorCodeUserNotFound
错误(与您使用的17011代码相匹配)“表示未找到用户帐户。如果用户帐户已被删除,则可能发生这种情况。”我不清楚这是否是引发该错误的唯一情况……无论如何,更深入地了解你正在尝试做的事情的根源……在我看来,你可能正在尝试处理他们为你处理的事情。对于
createUserWithEmail
方法来说,它会抛出一个
FirautherRorCodeEmailalReadyUse
错误,这似乎就是您试图自己处理的问题。为什么不试着创建它并处理这个错误呢?@dbburges你知道它是什么吗?我在这行中缺少了一个空格:
…使用电子邮件登录(输入,密码:)…
因为
密码
没有空格firebase没有将其作为空密码读取,而更像是
nil
,这样就不会引发错误。谢谢你的帮助!再次感谢你令人惊讶的回答,希望其他与此斗争的人也会投票!