Reputation: 243
I want my method to wait until Firebase request finished
uploadSingUpInfo
returns before the Firebase request finishes, and this is a problem for me - some method returns nil.
static func uploadSingUpInfo(fullName:String,email:String,password:String)->String{
rootRef = FIRDatabase.database().reference()
var returnVlue="not valid"
FIRAuth.auth()?.createUserWithEmail(email, password: password) { (user, error) in
if (error != nil){
returnVlue=(error?.userInfo["error_name"]) as! String
}
else{
let newUser = [
"username": fullName
]
rootRef.childByAppendingPath("User")
.childByAppendingPath((user?.uid)!).setValue(newUser)
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isLogin")
NSUserDefaults.standardUserDefaults().setObject(email, forKey: "email")
NSUserDefaults.standardUserDefaults().setObject(user?.uid, forKey: "user_ID")
print(NSUserDefaults.standardUserDefaults().objectForKey("user_ID"))
returnVlue="valid"
}
}
return returnVlue
}
Upvotes: 4
Views: 8943
Reputation: 989
Instead of returning a value from that function. You can call another function inside the firebase method at the "very end" of the method. This will ensure that whatever function you need to do next, is executed at the end when Firebase is done processing your request
FIRAuth.auth()?.createUserWithEmail(email, password: password) { (user, error) in
if (error != nil){
returnVlue=(error?.userInfo["error_name"]) as! String
}
else{
let newUser = [
"username": fullName
]
rootRef.childByAppendingPath("User")
.childByAppendingPath((user?.uid)!).setValue(newUser)
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isLogin")
NSUserDefaults.standardUserDefaults().setObject(email, forKey: "email")
NSUserDefaults.standardUserDefaults().setObject(user?.uid, forKey: "user_ID")
print(NSUserDefaults.standardUserDefaults().objectForKey("user_ID"))
returnVlue="valid"
}
callAnotherFunctionWhenFinished()
}
Upvotes: 1
Reputation: 35648
Don't use Firebase as functions that return values - it goes against it's asynchronous nature.
Plan code structure that allows Firebase to perform it's task and then within the closure (block) go to the next step.
For example: In your code, change the function to not return anything and within the createUserBlock, as the last line instead of return, call the next function to update your UI.
static func uploadSingUpInfo(fullName:String,email:String,password:String) {
rootRef = FIRDatabase.database().reference()
FIRAuth.auth()?.createUserWithEmail(email, password: password) { (user, error) in
if (error != nil){
showUserAnError(error)
} else {
let newUser = [
"username": fullName
]
rootRef.childByAppendingPath("User")
.childByAppendingPath((user?.uid)!).setValue(newUser)
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isLogin")
NSUserDefaults.standardUserDefaults().setObject(email, forKey: "email")
NSUserDefaults.standardUserDefaults().setObject(user?.uid, forKey: "user_ID")
print(NSUserDefaults.standardUserDefaults().objectForKey("user_ID"))
continueLoginProcess() //reload the ui or whatever step is next
}
}
}
Upvotes: 5
Reputation: 3268
In your code, the method returns before the firebase request completes so the value of returnVlue
will not be set.
Normal Functions don't wait for async functions to finish running ;- because that's kind of the point of an async function. isn't it?
So if you want your uploadSingUpInfo
to wait until createUserWithEmail
has finished, then you have to make createUserWithEmail
an async function as well by using completionHandlers:
func uploadSingUpInfo(fullName: String, email: String, password: String, completion: (result: String) -> Void) {
FIRAuth.auth()?.createUserWithEmail(email, password: password) {
(user, error) in
if (error != nil){
returnVlue=(error?.userInfo["error_name"]) as! String
}
else{
let newUser = [
"username": fullName
]
rootRef.childByAppendingPath("User")
.childByAppendingPath((user?.uid)!).setValue(newUser)
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isLogin")
NSUserDefaults.standardUserDefaults().setObject(email, forKey: "email")
NSUserDefaults.standardUserDefaults().setObject(user?.uid, forKey: "user_ID")
print(NSUserDefaults.standardUserDefaults().objectForKey("user_ID"))
returnVlue="valid"
}
completion(returnVlue);
}
}
And this is how you would call this method :
uploadSingUpInfo(<arguments>) {
(result: String) in //this is what you pass to completion handler.
print("got back: \(result)")
}
See this article for a better idea.
Upvotes: 4