func checkUsername(username: String) -> Bool {
var avalible = true
Database.database().reference().child("usernames").child(username).observeSingleEvent(of: .value, with: { snapshot in
if snapshot.exists() {
print("exists")
avalible = false
}
})
return available
}
I'm trying to check if a username exists.
I've already tried multiple things, but it seems like the function always returns before the completion handler even finishes and always gives the same output (true) even if the username is already taken.
Does somebody have an idea how to „wait“ for the completion handler first to finish before returning the „available“ variable?
An explanation with the answer would be excellent.
Thanks.
CodePudding user response:
This is because the Firebase operation is asynchronous, you cannot simply turn that into a synchronous operation without blocking the thread.
Have a look at How could I create a function with a completion handler in Swift?
The correct way to approach this, without the use of the new async/await syntax, is to use a completion handler yourself.
func checkUsername(username: String, completion: @escaping (Bool) -> ()) {
Database.database().reference().child("usernames").child(username).observeSingleEvent(of: .value) { snapshot in
completion(!snapshot.exists())
}
}
// To use:
checkUsername(username: "foo") { exists in
print("exists? ", exists)
}
CodePudding user response:
You cannot return something from an asynchronous task. Your code – with fixed typos – returns true
even before the database request has been started.
Maybe there is a native async/await version of observeSingleEvent
but in any case you can use a Continuation
func checkUsername(username: String) async -> Bool {
return await withCheckedContinuation { continuation in
Database.database().reference().child("usernames").child(username).observeSingleEvent(of: .value, with: { snapshot in
continuation.resume(resume: !snapshot.exists())
})
}
}
And call it
Task {
let isAvailable = await checkUsername(username: "Foo")
}