Save User's name in Firebase - Swift - swift

I have three text field in my registration form. The e-mail id and password of the user are used by the Firebase SignUp method to create a new user. But I also want to save the user's name according to what they input.
My current code is;
#IBAction func registerPressed(_ sender: Any) {
SVProgressHUD.show(withStatus: "Setting you up")
dismissUIElements(value: false)
let currentUserName = userName.text
if currentUserName?.isEmpty == false {
FIRAuth.auth()?.createUser(withEmail: emailTextField.text!, password: passwordTextField.text!, completion: { (user, error) in
if error != nil {
print(error!)
SVProgressHUD.dismiss()
self.dismissUIElements(value: true)
} else {
print("Registration Successful!")
SVProgressHUD.dismiss()
self.dismissUIElements(value: true)
self.performSegue(withIdentifier: "goToSelectionFromRegister", sender: self)
}
})
}
else {
SVProgressHUD.dismiss()
SVProgressHUD.showError(withStatus: "Please enter your name!")
SVProgressHUD.dismiss(withDelay: 1)
self.dismissUIElements(value: true)
}
}

You need a function that will register the user and then create the child for that user in Firebase.
let databaseRef=//your path to users.
func registerUser(userUsername userName:String, userEmail email:String, userPassword password: String, userCreationComplete: #escaping (_ status: Bool, _ error: Error?) -> ()) {
Auth.auth().createUser(withEmail: email, password: password) { (user, error) in
guard let user = user else {
userCreationComplete(false, error)
return
}
let userData = ["userName": userName.text] as [String : Any]
ref.child(user.uid).updateChildValues(userData)
userCreationComplete(true, nil)
}
}
Then you call the function from within registerPressed() and you pass it the textfield values but make sure that none of them is empty.

You will create a new data table that stores that info. It won't be done in the create user function.
// create a reference to the DB
ref = Database.database().reference(fromURL: "https://your-project-name.firebaseio.com/")
//variables to store data
var myID : String?
var myName : String?
var myNumber : String?
var myEmail : String?
// creating the save user function
func saveUser(_ completion: #escaping(_ error: Error?) -> Void) {
if PageDataSource.sharedInstance.crudIsAvailable == true {
let usersRef = ref.child("users")
let myUserRef = usersRef.child(id)
myUserRef.updateChildValues(["User ID": id,
"Name": myName,
"Email": myEmail,
"Phone": .myNumber], withCompletionBlock: { (error, ref) in
if error != nil {
completion(error!)
} else {
completion(nil)
}
})
} else {
completion(NSError(domain: "Unavailable", code: 0, userInfo: nil))
}
}
// call the method like this to perform the save
func storeUser(completion: #escaping(_ completed: Bool, _ error: NSError?)-> Void) {
if let user = Auth.auth().currentUser {
myID = user.uid
myName = user.displayName
myEmail = user.email
// etc.,
completion(true,nil)
} else {
completion(false,NSError(domain: "No Current User", code: 1, userInfo: nil))
}
}

Related

an alert function that i created is calling several times for no reason

I am working on a project using firebase database and I save the users with their displayName instead of uid. I check if the displayName of the user who is trying to signup is on the list of displayNames on firebase and if not I allow user to signup with that displayName.
here is my signUp function;
func signUp(email: String, password: String) {
//gets the user data in the firebase
Database.database().reference().child("users").observe(.value) { [self] (snapshot) in
if snapshot.hasChild(self.userNameTxtField.text!){ //checking the displayName
self.present(alertFunction(message: "Seçmiş olduğunuz kullanıcı adı daha önceden alınmış."), animated: true)
} else {
Auth.auth().createUser(withEmail: email, password: password) { (authResult, error) in
if let error = error as NSError? {...} else {
self.signIn(email: email, password: password)
}
}
}
}
}
and here is my signIn function;
func signIn(email: String, password: String) {
Auth.auth().signIn(withEmail: email, password: password) { (authResult, error) in
if let error = error as NSError? {...} else {
self.activityIndicator.stopAnimating()
self.view.isUserInteractionEnabled = true
//create database reference
self.ref = Database.database().reference()
//create new child and write a value on the existance child
if self.userNameTxtField.text == ""{
print("User Name can not be nill!")
self.present(self.alertFunction(message: "Kullanıcı adı boş bırakılamaz"), animated: true)
} else {
UserDefaults.standard.setValue(true, forKey: "userSignedIn")
if let currentUser = Auth.auth().currentUser?.createProfileChangeRequest() {
currentUser.displayName = self.userNameTxtField.text!
currentUser.commitChanges(completion: { error in
if let error = error {
print(error)
} else {
print("DisplayName changed")
self.ref.child("users").child(currentUser.displayName!).setValue(["nickname": self.userNameTxtField.text ?? ""])
self.ref.child("users/\(currentUser.displayName!)/step_count").setValue(Int(0))
self.ref.child("users/\(currentUser.displayName!)/total_point").setValue(Int(0))
self.ref.child("users/\(currentUser.displayName!)/onesignal_player_id").setValue("")
self.performSegue(withIdentifier: "showMainFromRegister", sender: self)
}
})
}
}
}
}
}
and finally here is my actionFunction;
func alertFunction(message: String) -> UIAlertController {
let alert = UIAlertController(title: "Uyarı!", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Tamam", style: .cancel, handler: nil))
self.activityIndicator.stopAnimating()
self.view.isUserInteractionEnabled = true
return alert
}
I call the signUp function after a button clicked and signUp func is calling the signIn function and if everything goes fine signIn function calls the performSegue function but after the performSegue
snapshot.hasChild(self.userNameTxtField.text!)
is triggered several time and the alert;
self.present(alertFunction(message: "Seçmiş olduğunuz kullanıcı adı daha önceden alınmış."), animated: true)
is displaying for no reason.
How can I solve the problem?
Replace
// listens for any change
.observe(.value) { [self] (snapshot) in
with
// listens for a change only once
.observeSingleEvent(of: .value, with: { [weak self] snapshot in

Does not add a user to Firebase

I am trying to add users to my Firebase cloud
I connected my project to the console.firebase
While I fill in the email and password it is not adding to my firebase.
I have the following code:
#IBAction func registerButton(_ sender: Any) {
signUp()
}
this is a button for register
and this is the func signup:
func signUp (){
let name = nameValue.text
let password = passwordValue.text
let email = emailValue.text
if (!password!.isEmpty && !email!.isEmpty) {
Auth.auth().createUser(withEmail: email ?? "", password: password ?? "") { (result, error) in
if error == nil {
if let result = result {
}
}
}
}
else {
showAlert()
}
}
Can anybody help to figure out this problem?
here is the solution to my problem:
if (!name!.isEmpty && !password!.isEmpty && !email!.isEmpty) {
Auth.auth().createUser(withEmail: email ?? "", password: password ?? "") { (authResult, error) in
if let e = error {
print(e.localizedDescription)
} else {
// self.performSegue(withIdentifier: "main", sender: self)
}
}
}

Firebase AuthUI returns nil for display name and email in Sign in with Apple

When I try to sign in with Apple, Firebase AuthUI returns nil for display name and email. Here's my code
lazy var authUI: FUIAuth? = {
let UIAuth = FUIAuth.defaultAuthUI()
UIAuth?.delegate = self
UIAuth?.shouldHideCancelButton = true
return UIAuth
}()
func presentLogin(){
// providers
var providers: [FUIAuthProvider] = [
FUIEmailAuth(),
FUIGoogleAuth(),
FUIFacebookAuth()
]
if #available(iOS 13.0, *) {
let appleProvider = FUIOAuth.appleAuthProvider()
providers.append(appleProvider)
}
self.authUI?.providers = providers
let loginController = self.authUI!.authViewController()
present(loginController, animated: true, completion: nil)
}
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
print(authDataResult?.user.displayName)
}
I had the same issue! I don't have the Apple sign in, but even just with Firebase it would show nil for this information. My issue was that I hadn't properly set up the data for Firebase and Xcode to talk. You code seems right, but it looks like you might be missing a few things..? You're more experienced than me, so I might be wrong! But here's my code...
// SIGN UP FUNCTION, first name, last name, email, password
let db = Database.database().reference()
func signUp(firstName: String, lastName: String, email: String, password: String, completion: #escaping (LocalUser?, Error?) -> Void) {
let usersRef = db.child("users")
Auth.auth().createUser(withEmail: email, password: password) {[weak self] (result, error) in
if let uid = result?.user.uid {
let newUser: [String: String] = ["firstName": firstName, "lastName": lastName, "email": email]
let newLocalUser = LocalUser(firstName: firstName, lastName: lastName, email: email)
usersRef.child(uid).setValue(newUser){(error: Error?, ref: DatabaseReference) in
completion(newLocalUser, error)
}
} else {
completion(nil, nil)
}
}
}
// SIGN IN FUNCTION, email, password
func signIn(email: String, password: String, completion: #escaping (LocalUser?, Error?) -> Void) {
let usersRef = db.child("users")
Auth.auth().signIn(withEmail: email, password: password) { [weak self]
(result, error) in
guard let user = result?.user else {
completion(nil, error)
return
}
let uid = user.uid
usersRef.child(uid).observeSingleEvent(of: .value) { (snapshot) in
let value = snapshot.value as? [String: Any]
if let user = value {
let userObject = LocalUser.makeObjectFrom(user)
newUser = userObject
completion(userObject, nil)
} else {
completion(nil, error)
}
}
}
}
I didn't see a reference to the db and uid, so this may help!

How do I update UILabels synchronously with Firestore data?

I'm currently building an iOS app that will synchronize account information from Firestore. I have the login/register process hooked up and working. However, I need help understanding how to update my logInOutBtn, fullNameTxt and emailTxt in my MenuVC automatically when an user logs in/out. Currently, it will update whenever I close then reopen the menu, but what should I use to automatically update it without having to close the menu? Thanks!
// MenuVC
override func viewDidAppear(_ animated: Bool) {
if let user = Auth.auth().currentUser , !user.isAnonymous {
// We are logged in
logInOutBtn.setTitle("Logout", for: .normal)
if UserService.userListener == nil {
UserService.getCurrentUser {
self.fullNameTxt.text = UserService.user.fullName
self.emailTxt.text = UserService.user.email
}
}
} else {
logInOutBtn.setTitle("Login", for: .normal)
self.fullNameTxt.text = "Sign in or create an account"
self.emailTxt.text = "to continue."
}
}
fileprivate func presentLoginController() {
let storyboard = UIStoryboard(name: Storyboard.LoginStoryboard, bundle: nil)
if #available(iOS 13.0, *) {
let controller = storyboard.instantiateViewController(identifier: StoryboardId.LoginVC)
present(controller, animated: true, completion: nil)
} else {
// Fallback on earlier versions
}
}
#IBAction func logInOutClicked(_ sender: Any) {
guard let user = Auth.auth().currentUser else { return }
if user.isAnonymous {
presentLoginController()
} else {
do {
try Auth.auth().signOut()
UserService.logoutUser()
Auth.auth().signInAnonymously { (result, error) in
if let error = error {
debugPrint(error)
Auth.auth().handleFireAuthError(error: error, vc: self)
}
self.presentLoginController()
}
} catch {
debugPrint(error)
Auth.auth().handleFireAuthError(error: error, vc: self)
}
}
}
// UserService
func getCurrentUser(completion: #escaping () -> ()) {
guard let authUser = auth.currentUser else { return }
let userRef = db.collection("users").document(authUser.uid)
userListener = userRef.addSnapshotListener({ (snap, error) in
if let error = error {
debugPrint(error.localizedDescription)
return
}
guard let data = snap?.data() else { return }
self.user = User.init(data: data)
completion()
})
// User Model
struct User {
var fullName: String
var address: String
var id: String
var email: String
var stripeId: String
init(fullName: String = "",
address: String = "",
id: String = "",
email: String = "",
stripeId: String = "") {
self.fullName = fullName
self.address = address
self.id = id
self.email = email
self.stripeId = stripeId
}
init(data: [String : Any]) {
fullName = data["fullName"] as? String ?? ""
address = data["address"] as? String ?? ""
id = data["id"] as? String ?? ""
email = data["email"] as? String ?? ""
stripeId = data["stripeId"] as? String ?? ""
}
static func modelToData(user: User) -> [String : Any] {
let data : [String : Any] = [
"fullName" : user.fullName,
"address" : user.address,
"id" : user.id,
"email" : user.email,
"stripeId" : user.stripeId
]
return data
}
}
// My app menu
The signout process is pretty straightforward and is marked as throws so if it fails, it will generate an error that can be handled by a catch. It is not asynchronous so it won't have (or need) a closure.
So simply stated
func signOut() {
let firebaseAuth = Auth.auth()
do {
try firebaseAuth.signOut()
print("successful signout")
self.logInOutBtn.setTitle("Log In", for: .normal)
self.fullNameTxt.text = ""
self.emailTxt.text = ""
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
//present the error to the user/handle the error
}
}
The signIn function is asynchronous with a closure so when the user signs in successfully, the code in the closure will fire and that's the perfect place to update the UI.
Auth.auth().signIn(withEmail: email, password: password) { [weak self] authResult, error in
guard let strongSelf = self else { return }
// update the UI here.
}
You can also just monitor the authState with an observer and have it react to users logging in/out
self.authListener = Auth.auth()?.addAuthStateDidChangeListener { auth, user in
if let theUser = user {
print("User logged in \(theUser)") // User is signed in.
self.dismissViewControllerAnimated(true, completion: nil)
} else {
print("Need to login.") // No user is signed in.
//present login view controller
}
}
If you no longer want to observe the auth state, you can remove it with
Auth.auth()?.removeAuthStateDidChangeListener(self.authListener)

Cannot convert value of type '(User?, _) -> ()' to expected argument type.i am struggling to resolve that error

Hey guys i am struggling to resolve this error actually i am trying to send these 4 strings and one picture to firebase and this was working fine until this error came up.
guard let email = emailTextField.text, let password = passwordTextField.text, let name = nameTextField.text else {
print("Form is not valid")
return
}
Auth.auth().createUser(withEmail: email, password: password, completion: { (user:User?, error) in
if error != nil {
print(error!)
return
}
guard let uid = user?.uid else {
return
}
//successfully authenticated user
let imageName = UUID().uuidString
let storageRef = Storage.storage().reference().child("profile_images").child("\(imageName).jpg")
if let profileImage = self.profileImageView.image, let uploadData = UIImageJPEGRepresentation(profileImage, 0.1) {
// if let uploadData = UIImagePNGRepresentation(self.profileImageView.image!) {
storageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil {
print(error!)
return
}
if let profileImageUrl = metadata?.downloadURL()?.absoluteString {
let values = ["name": name, "email": email, "profileImageUrl": profileImageUrl]
self.registerUserIntoDatabaseWithUID(uid, values: values as [String : AnyObject])
}
})
}
})
}
fileprivate func registerUserIntoDatabaseWithUID(_ uid: String, values: [String: AnyObject]) {
let ref = Database.database().reference()
let usersReference = ref.child("users").child(uid)
usersReference.updateChildValues(values, withCompletionBlock: { (err, ref) in
if err != nil {
print(err!)
return
}
If you write a type of user parameter (user: User?) you also have to write the types of other parameters (error: Error?)
Auth.auth().createUser(withEmail: email, password: password) { (user: User?, error: Error?)
in ...
}
Also you may write by this way:
Auth.auth().createUser(withEmail: email, password: password) { user, error in
...
}