Ethan Ethan - 4 months ago 20
iOS Question

iOS Async Task Issue When Returning Firebase Usernames

I'm so close to accomplishing this part of my project. I've learned a lot, but just can't see, to wrap this up. What I am trying to do is essentially check if an email address is already being used by another user. To accomplish this, I am using this code:

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


This whole
Async
thing is only 6 hours old to me, so if you have any suggestions please let me know. But this function is then called when a button is pressed, just by doing this:

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


For some reason, this is returning empty, not
true
,
false
or even
nil
. It just returns
()
However it does return
Wrong Password
when I do pass in the right password, not quite sure if thats relevant. Can anybody lend a hand with this? Thanks everybody!

Added Info
After suggestions, the code and the reference to the code now looks like this: (Only included important parts)

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


The though process behind this is that if the code returned is that the user doesn't exists, then the email account is open to be resisted with, thus allowing
canRegister
, otherwise, if the empty password passed into it is incorrect, then we know that the account exists and is therefore not open to be registered using. Currently,
canRegister
returns the value equal to whatever it is defined as here:

var canRegister = false


Back in the function call.

Answer

You are printing the return value of emailCheck, which isn't quite what you want. Async just means that portion of code will be run at some later time. Consider this simple function:

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

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

  return valid
}

This simply checks if an email has more than zero characters. It could be simplified significantly, but I've made it a bit more verbose to illustrate the differences. To use it, you'd simply do something like this:

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

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

If we want the method to be able to do work asynchronously, we'd provide it a callback. A callback is just a function that can be called to let us know what the results were, instead of them being returned directly by the function. Here is what that looks like:

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)

Note that emailCheck no longer returns a value, but actually executes the callback method with the result. This isn't truly asynchronous yet, because the callback is executed right away, but it lets us do asynchronous things if we want to.

Swift has some neat syntactical sugar for passing callbacks as the last parameter without declaring them explicitly like I did above. This is what you are using for Firebase's signInWithEmail method. Using that in this code, it looks like this:

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

It does exactly the same thing, but I think it looks a little nicer in this case. So now we have a good setup that can check the email, and some code that can run later once we know if the email is valid or not. Putting it all together:

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

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