I added a line of code so that name text-field is mandatory when registering an account with firebase but when I did that the UIAlert broke. It stopped showing up when I added that line of code. The code I added is highlighted with a >. What is the best way to fix the problem? Either recode the mandatory name text-field or recode the UIAlert. Which is the simplest way?
#IBAction func registerTapped(_ sender: Any) {
let namec = nameTextField.text
if let email = emailTextField.text, let pass = passwordTextField.text, let name = (namec?.capitalized.isEmpty)! ? nil:namec?.capitalized {
FIRAuth.auth()?.createUser(withEmail: email, password: pass, completion: { (user, error) in
if user != nil {
//user found
let interval = NSDate().timeIntervalSince1970
let date = Date(timeIntervalSince1970: interval)
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy/HH/mm/SS"
// you can change the date format to whatever you wants
let dateString = dateFormatter.string(from: date)
print(dateString)
self.refD?.child("Users").child((user?.uid)!).setValue(["Email": email, "Name": name, "User Created": dateString])
print("User Created And Added To Database", email, name, dateString)
self.performSegue(withIdentifier: "registertologin", sender: self)
}
else {
print(error!)
let alert = UIAlertController(title: "Error Creating Account ", message: "\(error!.localizedDescription)", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
})
}
}
}
i think you have to add alert code in the main queue block because your code is inside a completion handler block
DispatchQueue.main.async {
print(error!)
let alert = UIAlertController(title: "Error Creating Account ", message: "\(error!.localizedDescription)", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
Try this!
Related
I have an app that allows users to save their profile. In order for them to be able to sign up, I want to check and see if they have agreed to the apps terms and conditions. The issue I am having is if the user doesn't agree to them, they will see an alertController telling them to agree. However, the app still continues to execute the remainder of the code.
func checkIfChecked() {
if self.checkbox.imageView.isHidden == true {
let alert = UIAlertController(title: "Hold up!",message:" You must agree to our Community Guidelines before you can sign up.", preferredStyle: UIAlertController.Style.alert)
let continueButton = UIAlertAction(title: "Got it!", style: .default, handler: {(_ action: UIAlertAction) -> Void in
})
continueButton.setValue(GREEN_Theme, forKey: "titleTextColor")
alert.addAction(continueButton)
self.present(alert, animated: true, completion: nil)
}
if self.checkbox2.imageView.isHidden == true {
let alert = UIAlertController(title: "Hold up!",message:" You must agree to our Terms & Conditions before you can sign up.", preferredStyle: UIAlertController.Style.alert)
let continueButton = UIAlertAction(title: "Got it!", style: .default, handler: {(_ action: UIAlertAction) -> Void in
})
continueButton.setValue(GREEN_Theme, forKey: "titleTextColor")
alert.addAction(continueButton)
self.present(alert, animated: true, completion: nil)
}
}
#objc func handleRegister() {
checkIfChecked()
let hud = JGProgressHUD(style: .dark)
hud.textLabel.text = "Registering!"
hud.show(in: view)
guard let email = emailTextField.text, let password = passwordTextField.text, let name = nameTextField.text, let phonenumber = phonenumberTextField.text else {
print("Error")
return
the remainder of code....
}
}
if the checkBoxs are checked, there is no issue. But if they are not checked, then the users information will still be saved to the data base without them logging in. So I am trying to stop the execution of handleRegister after checkIfChecked is called only if the boxs were not checked.
Not sure if this is the safest way to fix the issue I am having, but what I did to fix the problem is inside of of the handleRegister, I added
checkIfChecked()
this has to be after the checkIfChecked that way the alertControllers can show.
if self.checkbox.imageView.isHidden == true {
return
} else if self.checkbox2.imageView.isHidden == true {
return
}
it does stop the execution of code if these lines are true.
The alert function is not called but there are no errors
#objc func handleSignUp(){
guard let email = emailTextField.text else {
let alertemail = UIAlertController(title: "Error!", message: "Please enter a valid email address!", preferredStyle: UIAlertController.Style.alert)
let actionemail = UIAlertAction(title: "OK", style: .default) { (actionemail) in
alertemail.dismiss(animated: true, completion: nil)
}
alertemail.addAction(actionemail)
self.present(alertemail, animated: true, completion: nil)
return
}
guard let password = passwordTextField.text else {
let alertpassword = UIAlertController(title: "Error!", message: "Please enter a valid password!", preferredStyle: UIAlertController.Style.alert)
let actionpassword = UIAlertAction(title: "OK", style: .default) { (actionpassword) in
alertpassword.dismiss(animated: true, completion: nil)
}
alertpassword.addAction(actionpassword)
return
}
createUser(withEmail: email, password: password)
}
The text property of an UITextField object (unlike UILabel) is never nil. This string is #"" by default.
You could add a check if the string is empty
guard let email = emailTextField.text, !email.isEmpty else { ...
However you should validate the email address
I have just coded a signup page in which if user does not enter text in any of the uitextfield then it should receive an error message (UIAlert) ; else (if user enter text in all uitextfield) signup page will present for Firebase Authentication.
in my code, user will direct to sign-in page only if authentication successfully complete else it should remain in signup page with alert message.
Problem - my code is able to produce alert message but same time it is taking user to sign-in page automatically even when there is an error. which means it is performing a segue that takes user to sign-in page i.e. segue unwinding irrespective of alert message.
can anyone help me why this may be happening?
#IBAction func registerPressed(_ sender: Any) {
if nameText.text!.isEmpty || genderText.text!.isEmpty || countryText.text!.isEmpty || yourSchool.text!.isEmpty || yourClass.text!.isEmpty {
print("Please fill all fields") //my code is printing this error
//alert message popup - my code is ble to produce this alert but same it is performing segue and taking user to signin page
//ideally, i want user to be in signup page unless all criteria meet
let alertController = UIAlertController(title: "Error", message: "Please fill all fields", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action:UIAlertAction) in
print("Okay")
}))
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)
}
else {
Auth.auth().createUser(withEmail: yourEmail.text!, password: yourPassword.text!) { (user, error) in
if error != nil {
///print errror message
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action:UIAlertAction) in
print("Okay")
}))
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert + 1;
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)
}
else {
print("You have successfully signed up")
self.performSegue(withIdentifier: "JoinUs2SignPage", sender: self)
//updating user information
let userID = Auth.auth().currentUser!.uid
let usertype: String = "Student"
self.ref.child("users").child(userID).setValue(["usertype": usertype ,"username": self.nameText.text!, "usergender": self.genderText.text!, "usercountry": self.countryText.text!, "userschool": self.yourSchool.text!, "userclass": self.yourClass.text!,])
}
}
}
}
From this bit of code it doesn't really look like anything is wrong. However, you should block the UI while Auth.auth().createUser(...) is running. Otherwise there's a chance that you call registerPressed with everything correct, but then delete the text from a label and call it again before the callback. That way you have an alert and then the segue is called.
You're also doing something quite crazy with the way that you're presenting your alerts. Instead of creating a new window, adding to it a view controller and all that jazz, just call self.present(alertController, animated: true). E.g.
let alertController = UIAlertController(title: "Error", message: "Please fill all fields", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action:UIAlertAction) in
print("Okay")
}))
self.present(alertController, animated: true)
Remove the segue and push to destination view controller programmatically.
self.navigationController?.pushViewController(destinationVC, animated: true)
I was doing a silly mistake where I created the segue directly on IBAction and hence whenever I was pressing the button it was performing the segue irrespective UIAlerts. my updated code is below :
#IBAction func registerPressed(_ sender: Any) {
if nameText.text!.isEmpty || genderText.text!.isEmpty || countryText.text!.isEmpty || yourSchool.text!.isEmpty || yourClass.text!.isEmpty {
//alert message popup
let alertController = UIAlertController(title: "Error", message: "Please fill all fields", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action:UIAlertAction) in
print("Okay")
}))
self.present(alertController, animated: true, completion: nil)
}
else {
Auth.auth().createUser(withEmail: yourEmail.text!, password: yourPassword.text!) { (user, error) in
if error != nil {
///print errror message
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action:UIAlertAction) in
print("Okay")
}))
self.present(alertController, animated: true, completion: nil)
}
else {
let alertController = UIAlertController(title: "Congratulation", message: "You have successfully signed up", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Get Started", style: .default, handler: { (action:UIAlertAction) in
self.performSegue(withIdentifier: "back2SignPage", sender: self)
}))
self.present(alertController, animated: true, completion: nil)
//updating user information
let userID = Auth.auth().currentUser!.uid
let usertype: String = "Student"
self.ref.child("users").child(userID).setValue(["usertype": usertype ,"username": self.nameText.text!, "usergender": self.genderText.text!, "usercountry": self.countryText.text!, "userschool": self.yourSchool.text!, "userclass": self.yourClass.text!,])
}
}
}
}
more specifically the error warning I ma getting is:
Attempt to present UIAlertController whose view is not in the window hierarchy!
I am currently creating a signup page that ask user to fill few specific details such as Name, Country, Email, Password and etc. To make sure user provide all the relevant information I am trying to write a code to send an alert if user does not provide all the information. I have wrote the code taking help from stakeoverflow.
Problem: Whenever user left any field blank it is not showing the alert and by default performing a segue that takes user to signin page. This is the first time I am creating an alert and hence don't what is going wrong (I believe 95% of my code is in place)
can anyone help?
#IBAction func signUpPressed(_ sender: Any) {
if nameText.text!.isEmpty || genderText.text!.isEmpty || countryText.text!.isEmpty || yourSchool.text!.isEmpty || yourClass.text!.isEmpty {
print("Please fill all fields")
//my code is printing above error in the Xcode console but the below code is not working
//setting error message if not all fiels filled
let alertController = UIAlertController(title: "Error", message: "Please fill all fields", preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
present(alertController, animated: true, completion: nil)
}
else {
Auth.auth().createUser(withEmail: yourEmail.text!, password: yourPassword.text!) { (user, error) in
if error != nil {
///print errror message
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
} else {
print("You have successfully signed up")
self.performSegue(withIdentifier: "JoinUs2SignPage", sender: self)
//updating user information
let userID = Auth.auth().currentUser!.uid
let usertype: String = "Student"
self.ref.child("users").child(userID).setValue(["usertype": usertype ,"username": self.nameText.text!, "usergender": self.genderText.text!, "usercountry": self.countryText.text!, "userschool": self.yourSchool.text!, "userclass": self.yourClass.text!,])
}
}
}
Action may be out of main thread
DispatchQueue.main.async {
///print errror message
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .cancel, handler: nil)
alertController.addAction(defaultAction)
self.present(alertController, animated: true, completion: nil)
}
Try this approach
check for white space like that
let nameTrimmed = self.nameText.text?.trimmingCharacters(in: .whitespacesAndNewlines)
let genderTrimmed = self.genderText.text?.trimmingCharacters(in: .whitespacesAndNewlines)
let countryTrimmed = self.countryText.text?.trimmingCharacters(in: .whitespacesAndNewlines)
let schoolTrimmed = self.schoolText.text?.trimmingCharacters(in: .whitespacesAndNewlines)
if nameTrimmed.text == "" || genderTrimmed.text == "" || countryTrimmed.text == "" || schoolTrimmed.text == ""
#IBAction func registerPressed(_ sender: Any) {
if nameText.text!.isEmpty || genderText.text!.isEmpty || countryText.text!.isEmpty || yourSchool.text!.isEmpty || yourClass.text!.isEmpty {
print("Please fill all fields") //my code is printing this error
//alert message popup
let alertController = UIAlertController(title: "Error", message: "Please fill all fields", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action:UIAlertAction) in
print("Okay")
}))
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)
}
else {
Auth.auth().createUser(withEmail: yourEmail.text!, password: yourPassword.text!) { (user, error) in
if error != nil {
///print errror message
let alertController = UIAlertController(title: "Error", message: error?.localizedDescription, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .default, handler: { (action:UIAlertAction) in
print("Okay")
}))
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert + 1;
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alertController, animated: true, completion: nil)
}
else {
print("You have successfully signed up")
self.performSegue(withIdentifier: "JoinUs2SignPage", sender: self)
//updating user information
let userID = Auth.auth().currentUser!.uid
let usertype: String = "Student"
self.ref.child("users").child(userID).setValue(["usertype": usertype ,"username": self.nameText.text!, "usergender": self.genderText.text!, "usercountry": self.countryText.text!, "userschool": self.yourSchool.text!, "userclass": self.yourClass.text!,])
}
}
}
}
I'm stuck with email verification with firebase. I've looked around for guidance but no help. After the user verifies his email, my code still prints out the user has not been verified. I'm still trying to get used to the syntax of firebase. Here is my code:
if FIRAuth.auth()?.currentUser!.emailVerified == true{
FIRAuth.auth()?.signInWithEmail(email.text!, password: passsword.text!, completion: {
user, error in
if error != nil{
print("Email/password is wrong or user does not exist")
}else{
print("Successful login.")
}
})
}else{
print("Please verify your email.")
}
here is my code for the sign up section:
let eduEmail = email.text
let endInEdu = eduEmail?.hasSuffix("my.utsa.edu")
if endInEdu == true {
FIRAuth.auth()?.createUserWithEmail(email.text!, password: passsword.text!, completion: {
user, error in
if error != nil{
let alert = UIAlertController(title: "User exists.", message: "Please use another email or sign in.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
print("Email has been used, try a different one")
}else{
FIRAuth.auth()?.currentUser!.sendEmailVerificationWithCompletion({ (error) in
})
let alert = UIAlertController(title: "Account Created", message: "Please verify your email by confirming the sent link.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
print("This is a college email and user is created")
}
})
}else{
print("This is not a my.utsa.edu email")
}
You checked if the user email was verified even before signing them in.
This is what worked for me.
FIRAuth.auth()?.signInWithEmail(txtUsername.text!, password: txtPassword.text!) {
(user, error) in
if let user = FIRAuth.auth()?.currentUser {
if !user.emailVerified{
let alertVC = UIAlertController(title: "Error", message: "Sorry. Your email address has not yet been verified. Do you want us to send another verification email to \(self.txtUsername.text).", preferredStyle: .Alert)
let alertActionOkay = UIAlertAction(title: "Okay", style: .Default) {
(_) in
user.sendEmailVerificationWithCompletion(nil)
}
let alertActionCancel = UIAlertAction(title: "Cancel", style: .Default, handler: nil)
alertVC.addAction(alertActionOkay)
alertVC.addAction(alertActionCancel)
self.presentViewController(alertVC, animated: true, completion: nil)
} else {
print ("Email verified. Signing in...")
}
}
}
You are using the coalescing operator after FIRAuth.auth() which means the following method call will return nil when FIRAuth.auth() was nil. If this is the case, your comparison with true will fail, since nil is not true.
I suggest you to refactor your code like this for easier debugging:
guard let auth = FIRAuth.auth(), user = auth.currentUser else {
print("No auth / user")
}
guard user.emailVerified else {
print("Email not verified")
return
}
guard let email = email.text, password = passsword.text else {
print("No email or password")
return
}
auth.signInWithEmail(email, password: password) { user, error in
if let error = error {
print("Email/password is wrong or user does not exist, error: \(error)")
} else {
print("Successful login.")
}
}
You should find your error easier like this.