3

I have the following Firebase query where I check if a username already exists in a database. I would like to assign a boolean value (true) to a variable called usernameAlreadyExists. However, I need to access this variable with its new value outside of the closure. I read that I need to implement a completionHandler or a callback in order to do this. However, I don't know how to implement this in the Firebase query syntax :

var usernameAlreadyExists = false

FIRDatabase.database().reference().child("usernames").queryOrderedByValue().queryEqual(toValue: self.username.text).queryLimited(toFirst: 1).observe(.childAdded, with: { snapshot in

        // Username unavailable, chose another one
        self.invalidUsernameMsg.text = "This username already exists, please choose another one."
        print(snapshot)
        print(snapshot.value)
        usernameAlreadyExists = true

})

print(usernameAlreadyExists)

print(usernameAlreadyExists) --> I want this line to print "true", but it prints "false" because the code above is executed asynchronously.

Any help is more than welcome. Thank you!

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807

1 Answers1

0

You are seeing a false value when you print your userNameAlreadyExists variable because simply you are correct. The program will run through your code very fast including the printing, then when the Firebase finishes its query, it will add change the value of your userNameAlreadyExists to true.

Is this clear?

Also, for the call back or completion handler, you already have this in your Firebase code. The part snapshot in is the beginning of your completion handler.

If you want to print your variable to true, then put it inside the completion handler, like so:

var usernameAlreadyExists = false

FIRDatabase.database().reference().child("usernames").queryOrderedByValue().queryEqual(toValue: self.username.text).queryLimited(toFirst: 1).observe(.childAdded, with: { snapshot in

        // Username unavailable, chose another one
        self.invalidUsernameMsg.text = "This username already exists, please choose another one."
        print(snapshot)
        print(snapshot.value)
        usernameAlreadyExists = true
        print(usernameAlreadyExists)
})

EDIT: OP wants to validate the username if existing or not before registration.

  1. Detect when the user stops typing inside the username textField Reference: https://stackoverflow.com/a/29763089/3231194

  2. Inside the function the detection above, put your Firebase function you're using posted in your question, like so:

    func userDidStopTypingUsername() {
        // Firebase query here.
        // Then if existing, do something and store the value too in your bool variable.
    }
    
  3. Also, inside your IBAction or function of your Signup button, validate the userNameAlreadyExists too. If existing, then do something and return to prevent proceeding to signing up. Otherwise, proceed.

Community
  • 1
  • 1
Glenn Posadas
  • 12,555
  • 6
  • 54
  • 95
  • Thank you very much for the explanation prettyitgirl.com! However, I will need to access this variable outside of the closure. I represented this by a **print()** in the current example just to reflect the behaviour the code should have. But later on, I will need to use the changed value (from false to true) of the variable in my code. I will need to run some code depending on the value of the variable like so : **if usernameAlreadyExists { // Do something } else { // Do something else }**. Is there a way for me to accomplish this? Thanks again! –  Feb 08 '17 at 02:33
  • Hi, I assume you're doing this validation of `usernames` for your **sign up**, right? Or do you want to validate right away the username as soon as the user finishes or stops typing in the textField? – Glenn Posadas Feb 08 '17 at 02:38
  • That is correct. I want to validate the username before the user ever gets registered. The idea is that the user information will be written to the database at the end of the sign up process. This way, if the user kills the app in the middle of the process of signing up, no data will have been written to the DB. The code above lets me detect if a username is already taken in real-time. However, I need a way to check if the username is not taken, and as far as I know you can't do this with a Firebase query which is why I want to get the result of the query above and use it as a reference. –  Feb 08 '17 at 03:03
  • Hey, please check my edited answer. See if that's what you're trying to do. – Glenn Posadas Feb 08 '17 at 05:04
  • My problem is that the value of **userAlreadyExists** that I have to validate in the 3rd step of your answer is always equal to _"false"_ regardless of the existence of the same username in the DB or not. In other words, when I set my **userAlreadyExists** to _"true"_ in the Firebase query, I have access to this _"true"_ value of **userAlreadyExists** only within this Firebase query and so the entire code I want to use **userAlreadyExists** in must be within this Firebase query. I need to be able to use the _"true"_ value of **userAlreadyExists** outside of the query (need a callback). Thanks –  Feb 08 '17 at 23:43