segue performed before the UIAlertController in swift - ios

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!,])
}
}
}
}

Related

How to put a success or error alert inside an options alert?

I have a problem trying to put an alert message after completing the action. The application crashes.
#IBAction func deleteAccountAction(_ sender: Any) {
let userID = prefs.value(forKey: "userId") as! String
print("user id: \(userID)")
let alert = UIAlertController(title: "Delete account", message: "Are you sure you want to delete your account?, This action cannot be reversed.", preferredStyle: .alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
// ...
}
let okayAction = UIAlertAction(title: "OK", style: .default) { (action) in
RestAPIManager.sharedInstance.deleteAccount(userID: userID){
(json, error) in
if(json != JSON.null){
print(json)
if(json["success"] == true){
//here i want succes alert
}else{
self.errorAlert()
}
}else{
}
}
}
alert.addAction(okayAction)
alert.addAction(cancelAction)
self.present(alert, animated: true)
}
func errorAlert(){
var dialogMessage = UIAlertController(title: "Error", message: "Error", preferredStyle: .alert)
self.present(dialogMessage, animated: true, completion: nil)
}
I tried to put an alert message after the action but I can't.
is solved needs to be async.
DispatchQueue.main.async {
self.errorAlert()
}

Trouble implementing UIAlertController. Cant get alert to show up

I have set an alert to be shown as any error occurs when some user tries to request a new password through firebase, but it is not working.
The print("problems with email field") is being printed so I believe I have made something wrong when writing the alert part.
#IBAction func recuperarSenha(_ sender: Any) {
Auth.auth().sendPasswordReset(withEmail: self.loginTextView.text!) { error in
if error != nil {
print("problems with email field")
let alert = UIAlertController(title: "Couldn't send recover message", message: "Check if e-mail field is properly filled.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK!", style: .default, handler: nil))
}
}
}
You need to present your alert after creating it. Add the following code after adding action:
self.present(alert, animated: true, completion: nil)
Edited version of your code:
#IBAction func recuperarSenha(_ sender: Any) {
Auth.auth().sendPasswordReset(withEmail: self.loginTextView.text!) { error in
if error != nil {
print("problems with email field")
let alert = UIAlertController(title: "Couldn't send recover message", message: "Check if e-mail field is properly filled.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK!", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
}

Attempt to present UIAlertController whose view is not in the window hierarchy

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!,])
}
}
}
}

Segue after new user creation using firebase not being performed -Swift

I am having issues with two segues however, since I used the same logic in the implementation of each of these segues I'm going to go ahead and condense everything into one question. Basically, I am trying to initialize a segue after performing createUser function with firebase and after performing login function also handled by Firebase, however, when the SignUp and Login buttons are clicked there seems to be no response to the segue being called. Below is the code for each of the #IBActions
#IBAction func signUpComplete(_ sender: Any) {
FIRAuth.auth()?.createUser(withEmail: signUpEmailField.text!, password: signUpPasswordField.text!, completion: { (user: FIRUser?, error) in
if self.signUpEmailField.text == "" || self.signUpPasswordField.text == "" {
let alert = UIAlertController(title: "Oops!", message: "A valid E-mail and Password are Required", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
if FIRAuthErrorCode.errorCodeEmailAlreadyInUse != nil {
let emailExists = UIAlertController(title: "Oops!", message: "A user with this E-Mail already exists!", preferredStyle: UIAlertControllerStyle.alert)
emailExists.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
self.present(emailExists, animated: true, completion: nil)
}
else {
DispatchQueue.main.async () {
self.performSegue(withIdentifier: "signUpSucceededSegue", sender: self)
}
}
}
})
}
and
#IBAction func loginButton(_ sender: Any) {
FIRAuth.auth()?.signIn(withEmail: emailLoginField.text!, password: passwordLoginField.text!, completion: { (user: FIRUser?, error) in
if self.emailLoginField.text == "" || self.passwordLoginField.text == ""{
let alert = UIAlertController(title: "Alert", message: "E-Mail is Required", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
if FIRAuthErrorCode.errorCodeUserNotFound != nil {
let invalidLogin = UIAlertController(title: "Alert", message: "E-Mail/Password Incorrect", preferredStyle: UIAlertControllerStyle.alert)
invalidLogin.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
self.present(invalidLogin, animated: true, completion: nil)
}
else{
DispatchQueue.main.async () {
self.performSegue(withIdentifier: "loginSucceededSegue", sender: self)
}
}
}
})
are there any glaring logical errors at first glance or is there a better way to implement a segue into these functions?
Embed a Navigation Controller to the very first view of your storyboard
Then Try using this code:-
#IBAction func signUpComplete(_ sender: Any) {
if self.signUpEmailField.text == "" || self.signUpPasswordField.text == "" {
let alert = UIAlertController(title: "Oops!", message: "A valid E-mail and Password are Required", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}else{
FIRAuth.auth()?.createUser(withEmail: self.signUpEmailField!.text, password: self.signUpPasswordField!.text, completion: { (user, err) in
if let ErrorCode = FIRAuthErrorCode(rawValue: err!._code){
switch ErrorCode {
case .errorCodeEmailAlreadyInUse : let emailExists = UIAlertController(title: "Oops!", message: "A user with this E-Mail already exists!", preferredStyle: UIAlertControllerStyle.alert)
emailExists.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
self.present(emailExists, animated: true, completion: nil)
break
default : break
}
}else{
let nextView = self.navigationController!.storyboard!.instantiateViewController(withIdentifier: "signUpSucceededSegue")
self.navigationController!.pushViewController(nextView, animated: true)
}
})
}
}
Then alter your other code-block in the similar fashion.

Firebase login system

So here is the deal. Right now I have a viewcontroller where the user can signup, and it is working (checked in Firebase console). The next step is that I have another view with two fields and a Log in button. That login button now has a segue to the third view, home. But it is possible to click it even though nothing has been entered in the two textfields. The button should only work if the user enters his or he details he made in the signup view, thus logging in.
How can I do this?
already have the login code:
#IBAction func loginAction(sender: AnyObject)
{
if self.emailField.text == "" || self.passwordField.text == ""
{
let alertController = UIAlertController(title: "Oops!", message: "Please enter an email and password.", preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
else
{
FIRAuth.auth()?.signInWithEmail(self.emailField.text!, password: self.passwordField.text!) { (user, error) in
if error == nil
{
self.emailField.text = ""
self.passwordField.text = ""
}
else
{
let alertController = UIAlertController(title: "Oops!", message: error?.localizedDescription, preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
In the second if statement you see that it clears the fields to show the login worked.
What i need is that users can only login if the correct details are filled in, that are in the Firebase database.
Instead of checking if there isnt any errors, check that there is data is the user object like this.
FIRAuth.auth()?.signInWithEmail(self.emailField.text!, password: self.passwordField.text!) { (user, error) in
if user != nil
{
let VC = storyboard?.instantiateViewControllerWithIdentifier("Identifier") as! AccountViewController //The file that controls the view
self.presentViewController(VC, animated: true, completion: nil)
}
else
{
let alertController = UIAlertController(title: "Oops!", message: error?.localizedDescription, preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alertController.addAction(defaultAction)
self.presentViewController(alertController, animated: true, completion: nil)
}
I managed to fix it by adding self. infront of
storyboard?.instantiate.
Thus creating:
self.storyboard?instantiate.

Resources