17 Replies
      Latest reply on Apr 28, 2019 9:35 AM by Joel14
      Joel14 Level 1 Level 1 (0 points)

        I am having trouble with my app. The problem I am having is that when I leave a text field empty I want it to have a pop-up message that says empty text field and I want it to stop the segue from moving to the next screen. What is happening is it is showing the pop-up message of the empty text field but it still moves to the next screen. This is the code that I currently have:

         

           let firstNameAlert : UIAlertView = UIAlertView(title: "Blank Text Field", message: "Please fill in first name.",       delegate: nil, cancelButtonTitle: "OK")
                let lastNameAlert : UIAlertView = UIAlertView(title: "Blank Text Field", message: "Please fill in last name.",       delegate: nil, cancelButtonTitle: "OK")
                let emailAlert : UIAlertView = UIAlertView(title: "Blank Text Field", message: "Please fill in email.",       delegate: nil, cancelButtonTitle: "OK")
                let addressAlert : UIAlertView = UIAlertView(title: "Blank Text Field", message: "Please fill in address.",       delegate: nil, cancelButtonTitle: "OK")
                let phoneFromDefaults = defaults.object(forKey: "Phone Number") as? String
                
                if firstName.text == ""{
                    firstNameAlert.show()
                }else if lastName.text == ""{
                    lastNameAlert.show()
                }else if email.text == ""{
                    emailAlert.show()
                }else if addressLine1.text == ""{
                    addressAlert.show()
                }else{
                    performSegue(withIdentifier: "Create Account", sender: AnyObject.self)
                }
        
        • Re: Prevent Segue if Empty Text Field
          OOPer Level 8 Level 8 (5,005 points)

          Please show more context. Have you placed the segue from the source view controller? Isn't it from any of UI controls or cells?

          Also you should better show where in your code (which class? which method?) the lines you have shown exist.

          • Re: Prevent Segue if Empty Text Field
            Claude31 Level 8 Level 8 (5,775 points)

            Are you sure it is the

            performSegue(withIdentifier: "Create Account", sender: AnyObject.self)

             

            which is executd.

             

            Add a print just before to check:

             

            } else {
                 print("Will performSegue")
                 performSegue(withIdentifier: "Create Account", sender: AnyObject.self) 
            }
              • Re: Prevent Segue if Empty Text Field
                PBK Level 7 Level 7 (3,145 points)

                What Claude31 said and...

                       ....if it does print "Will performSegue" then add a similar print statement before the Alert.show(s) to be sure that is the line that is showing the Alert.

                 

                As written your code will do what you want it to.  That usually means 'the problem in the code is never where you are looking'.

                • Re: Prevent Segue if Empty Text Field
                  Joel14 Level 1 Level 1 (0 points)

                  I added the will perform segue print. However, when I test it out it does not print yet it still goes to the next screen and shows an error message for the blank text field.

                    • Re: Prevent Segue if Empty Text Field
                      Claude31 Level 8 Level 8 (5,775 points)

                      So you have another call to segue.

                      => Search everywhere for "segue" in your code

                       

                      Or may be you defined in IB ?

                           => Inspect in IB all the arrows going to the next screen

                        • Re: Prevent Segue if Empty Text Field
                          Joel14 Level 1 Level 1 (0 points)

                          I was able to find what was causing it to go to the next screen I had the segue set to show I changed it to custom. What is happening now is when I press the create account button but leave the text fields blank the app just crashes and doesn't show any pop up message.

                            • Re: Prevent Segue if Empty Text Field
                              Claude31 Level 8 Level 8 (5,775 points)

                              Please clarify.

                               

                              Have you defined the segue in IB ? (seems so)

                              Have you a segue AND an IBAction defined for the button ?

                              ==> You should not. You cannot have both.

                              So either

                              - define the segue from yje viewController (not starting from the button) and keep the IBAction as it is

                              - remove the IBAction and put the code for alerting in shouldPerformSegue ; return false in case of alert.

                               

                              And return to show segue

                                • Re: Prevent Segue if Empty Text Field
                                  Joel14 Level 1 Level 1 (0 points)

                                  What I did was I control-dragged from a button in one view controller to another then I selected the custom segue. I also for that button made an action and in that action, I put the code that I had showed earlier when I first had asked the question.

                                    • Re: Prevent Segue if Empty Text Field
                                      OOPer Level 8 Level 8 (5,005 points)

                                      control-dragged from a button in one view controller to another

                                       

                                      That is one thing you should not do when you want to manage the segue programmatically with `performSegue(withIdentifier:sender:)`.

                                       

                                      - Delete the existing segue

                                      - Add new segue control-dragging from the source view controller to another

                                        (Not from a button!)

                                      - Set the identifer of the new segue as the old one "Create Account"

                                      • Re: Prevent Segue if Empty Text Field
                                        Claude31 Level 8 Level 8 (5,775 points)

                                        You should not have both

                                        - a segue like this in IB from button to VC and

                                        - an IBAction.

                                         

                                        As I explained before:

                                        So either

                                        - define the segue from the viewController (not starting from the button) and keep the IBAction as it is

                                        - remove the IBAction and put the code for alerting in shouldPerformSegue ; return false in case of alert.

                                          • Re: Prevent Segue if Empty Text Field
                                            Joel14 Level 1 Level 1 (0 points)

                                            I did as you said by setting the segue from the view controller and keeping the code in the IBAction. But what is happening now is that it shows the pop-up message if there is a blank text field but once all text field is filled in and the user presses the create account button the app crashes.

                                              • Re: Prevent Segue if Empty Text Field
                                                Claude31 Level 8 Level 8 (5,775 points)

                                                Please, post the complete code for the controller.

                                                 

                                                Have you performed a Clean Build Folder after resetting the segues ?

                                                 

                                                How is segue precisely defined now ? Standard Show or Custom ?

                                                What is the exact crash message ?

                                                Check segue identifier, must be exactly the same as in code (including uppercase).

                                                If not matching, you'll get a crash with an error such as (here, account vs Account):

                                                Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver (<ViewController: 0x7f8bc3d0fff0>) has no segue with identifier 'Create account''

                                                 

                                                Another point: change the sender to self for instance, or sender (the IBAction sender)

                                                performSegue(withIdentifier: "Create Account", sender: self)

                                                 

                                                I would need to look at the rest of controller code to check if that could be the cause of crash

                                                  • Re: Prevent Segue if Empty Text Field
                                                    Claude31 Level 8 Level 8 (5,775 points)

                                                    Did you solve your issue ?

                                                    • Re: Prevent Segue if Empty Text Field
                                                      Joel14 Level 1 Level 1 (0 points)

                                                      Sorry, I haven't responded sooner I have just been very busy lately. This is the complete code:

                                                       

                                                      import UIKit
                                                      import FirebaseUI
                                                      import FirebaseAuth
                                                      import FirebaseDatabase
                                                      
                                                      class signInViewController: UIViewController{
                                                          //MARK: Properties
                                                          let defaults = UserDefaults.standard
                                                          let verificationID = UserDefaults.standard.string(forKey: "authVerificationID")
                                                          
                                                          @IBOutlet weak var phoneNumber: UITextField!
                                                          @IBOutlet weak var firstName: UITextField!
                                                          @IBOutlet weak var lastName: UITextField!
                                                          @IBOutlet weak var email: UITextField!
                                                          @IBOutlet weak var addressLine1: UITextField!
                                                          @IBOutlet weak var addressLine2: UITextField!
                                                          @IBOutlet weak var verificationCode: UITextField!
                                                          @IBOutlet weak var phoneNumberContinueButton: CustomButton!
                                                        
                                                          
                                                          //MARK: Sign In With Email
                                                          func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
                                                          {
                                                              if (textField == phoneNumber) {
                                                                  let newString = (textField.text! as NSString).replacingCharacters(in: range, with: string)
                                                                  let components = newString.components(separatedBy: NSCharacterSet.decimalDigits.inverted)
                                                                  let decimalString = components.joined(separator: "") as NSString
                                                                  let length = decimalString.length
                                                                  let hasLeadingOne = length > 0 && decimalString.character(at: 0) == (1 as unichar)
                                                                  
                                                                  if length == 0 || (length > 10 && !hasLeadingOne) || length > 11 {
                                                                      let newLength = (textField.text! as NSString).length + (string as NSString).length - range.length as Int
                                                                      
                                                                      return (newLength > 10) ? false : true
                                                                  }
                                                                  var index = 0 as Int
                                                                  let formattedString = NSMutableString()
                                                                  
                                                                  if hasLeadingOne {
                                                                      formattedString.append("1 ")
                                                                      index += 1
                                                                  }
                                                                  if (length - index) > 3 {
                                                                      let areaCode = decimalString.substring(with: NSMakeRange(index, 3))
                                                                      formattedString.appendFormat("(%@)", areaCode)
                                                                      index += 3
                                                                  }
                                                                  if length - index > 3 {
                                                                      let prefix = decimalString.substring(with: NSMakeRange(index, 3))
                                                                      formattedString.appendFormat("%@-", prefix)
                                                                      index += 3
                                                                  }
                                                                  
                                                                  let remainder = decimalString.substring(from: index)
                                                                  formattedString.append(remainder)
                                                                  textField.text = formattedString as String
                                                                  return false
                                                              }
                                                              else {
                                                                  return true
                                                              }
                                                          }
                                                          
                                                          override func viewDidLoad() {
                                                              super.viewDidLoad()
                                                          }
                                                          
                                                          @IBAction func passwordAuth(_ sender: Any) {
                                                              let authUI = FUIAuth.defaultAuthUI()
                                                              
                                                              guard authUI != nil else{
                                                                  //Log the error
                                                                  return
                                                              }
                                                              
                                                              authUI?.delegate = self
                                                              
                                                              let authViewController = authUI!.authViewController()
                                                              
                                                              present(authViewController, animated: true, completion: nil)
                                                          }
                                                          
                                                          //MARK: Phone Auth
                                                          @IBAction func sendPhoneAuthCode(_ sender: Any){
                                                              if let phoneNum = phoneNumber.text {    // No more need to unwrap phoneNum later
                                                                  
                                                                  
                                                                  PhoneAuthProvider.provider().verifyPhoneNumber(phoneNum, uiDelegate: nil) { (verificationID, error) in
                                                                      
                                                                      // Sign in using the verificationID and the code sent to the user
                                                                      // …
                                                                      //  if phoneNum == nil {
                                                                      if error != nil {
                                                                          print("verifyPhoneNumber went NOT OK")
                                                                          // REPLACE BY print       self.present(alert, animated: true, completion: nil)
                                                                          
                                                                          
                                                                          DispatchQueue.global(qos: .userInitiated).async {
                                                                              let titre = " Missing Information "
                                                                              let detailMsg = "Please enter your phone number"
                                                                              let controller = UIAlertController(title: titre, message: detailMsg, preferredStyle: .alert)
                                                                              
                                                                              let okAction = UIAlertAction(title: "OK", style: UIAlertAction.Style.cancel)
                                                                              controller.addAction(okAction)
                                                                              DispatchQueue.main.async {
                                                                                  self.present(controller, animated: true, completion: nil)
                                                                              }
                                                                              
                                                                          }
                                                                          
                                                                          
                                                                          return
                                                                      } else {
                                                                          print("verifyPhoneNumber went OK")
                                                                          // You have to test credential here, where do you do this ?
                                                                      }
                                                                  }
                                                              } else {
                                                                  print("phoneNumber.text is nil")
                                                                  return
                                                              }
                                                          }
                                                      
                                                          
                                                          @IBAction func enterVerificationCode(_ sender: Any){
                                                              let credential = PhoneAuthProvider.provider().credential(
                                                                  withVerificationID: verificationID!,
                                                                  verificationCode: verificationCode.text!)
                                                              
                                                              Auth.auth().signInAndRetrieveData(with: credential) { (authResult, error) in
                                                                  if error != nil {
                                                                      // ...
                                                                      return
                                                                  }
                                                                  // User is signed in
                                                                  // ...
                                                              }
                                                          }
                                                          
                                                          @IBAction func createAccount(_ sender: Any) {
                                                              let firstNameAlert : UIAlertView = UIAlertView(title: "Blank Text Field", message: "Please fill in first name.",       delegate: nil, cancelButtonTitle: "OK")
                                                              let lastNameAlert : UIAlertView = UIAlertView(title: "Blank Text Field", message: "Please fill in last name.",       delegate: nil, cancelButtonTitle: "OK")
                                                              let emailAlert : UIAlertView = UIAlertView(title: "Blank Text Field", message: "Please fill in email.",       delegate: nil, cancelButtonTitle: "OK")
                                                              let addressAlert : UIAlertView = UIAlertView(title: "Blank Text Field", message: "Please fill in address.",       delegate: nil, cancelButtonTitle: "OK")
                                                              
                                                              if firstName.text == ""{
                                                                  firstNameAlert.show()
                                                              }else if lastName.text == ""{
                                                                  lastNameAlert.show()
                                                              }else if email.text == ""{
                                                                  emailAlert.show()
                                                              }else if addressLine1.text == ""{
                                                                  addressAlert.show()
                                                              }else{
                                                                  print("Will performSegue")
                                                                  performSegue(withIdentifier: "Create Account", sender: self)
                                                              }
                                                          }
                                                      }
                                                      
                                                      extension signInViewController: FUIAuthDelegate{
                                                          func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
                                                              //Check if there was an error
                                                              if error != nil{
                                                                  //Log the error
                                                                  return
                                                              }
                                                              
                                                              authDataResult?.user.uid//Use for associating information in Firebase Database
                                                              
                                                              performSegue(withIdentifier: "passwordAuthLoggedIn", sender: self)
                                                          }
                                                      }
                                                      
                                                      

                                                       

                                                       

                                                      I did do a clean build.

                                                       

                                                      In response to if I have the correct name for the segue this was the error that I got:

                                                       

                                                       

                                                      Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not perform segue with identifier 'Create Account'. A segue must either have a performHandler or it must override -perform.'

                                                      *** First throw call stack:

                                                      (

                                                        0   CoreFoundation                      0x00000001041aa6fb __exceptionPreprocess + 331

                                                        1   libobjc.A.dylib                     0x000000010374eac5 objc_exception_throw + 48

                                                        2   UIKitCore                           0x0000000107b70392 -[UIStoryboardSegue _prepare] + 0

                                                        3   UIKitCore                           0x0000000107b70b9f -[UIStoryboardSegueTemplate _performWithDestinationViewController:sender:] + 276

                                                        4   UIKitCore                           0x0000000107b70a5d -[UIStoryboardSegueTemplate _perform:] + 82

                                                        5   UIKitCore                           0x00000001073d854b -[UIViewController performSegueWithIdentifier:sender:] + 99

                                                        6   UIKit                               0x0000000131efaec1 -[UIViewControllerAccessibility performSegueWithIdentifier:sender:] + 102

                                                        7   Drive Day                             0x00000001010e0fe9 $s7Drive_Day20signInViewControllerC13createAccountyyypF + 5001

                                                        8   Drive Day                             0x00000001010e11fc $s7Drive_Day20signInViewControllerC13createAccountyyypFTo + 76

                                                        9   UIKitCore                           0x00000001079d9204 -[UIApplication sendAction:to:from:forEvent:] + 83

                                                        10  UIKitCore                           0x000000010742ec19 -[UIControl sendAction:to:forEvent:] + 67

                                                        11  UIKitCore                           0x000000010742ef36 -[UIControl _sendActionsForEvents:withEvent:] + 450

                                                        12  UIKitCore                           0x000000010742deec -[UIControl touchesEnded:withEvent:] + 583

                                                        13  UIKitCore                           0x0000000107a11eee -[UIWindow _sendTouchesForEvent:] + 2547

                                                        14  UIKitCore                           0x0000000107a135d2 -[UIWindow sendEvent:] + 4079

                                                        15  UIKitCore                           0x00000001079f1d16 -[UIApplication sendEvent:] + 356

                                                        16  UIKit                               0x0000000131ea84af -[UIApplicationAccessibility sendEvent:] + 85

                                                        17  UIKitCore                           0x0000000107ac2293 __dispatchPreprocessedEventFromEventQueue + 3232

                                                        18  UIKitCore                           0x0000000107ac4bb9 __handleEventQueueInternal + 5911

                                                        19  CoreFoundation                      0x0000000104111be1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17

                                                        20  CoreFoundation                      0x0000000104111463 __CFRunLoopDoSources0 + 243

                                                        21  CoreFoundation                      0x000000010410bb1f __CFRunLoopRun + 1231

                                                        22  CoreFoundation                      0x000000010410b302 CFRunLoopRunSpecific + 626

                                                        23  GraphicsServices                    0x000000010c6cc2fe GSEventRunModal + 65

                                                        24  UIKitCore                           0x00000001079d7ba2 UIApplicationMain + 140

                                                        25  Drive Day                             0x00000001010fef5b main + 75

                                                        26  libdyld.dylib                       0x00000001060b1541 start + 1

                                                        27  ???                                 0x0000000000000001 0x0 + 1

                                                      )

                                                      libc++abi.dylib: terminating with uncaught exception of type NSException

                                                    • Re: Prevent Segue if Empty Text Field
                                                      Claude31 Level 8 Level 8 (5,775 points)

                                                      You have probably defined a custom segue.

                                                       

                                                      Then you need to define its class and override the perform method.

                                                       

                                                      Otherwise, just simply use a standard segue.

                                      • Re: Prevent Segue if Empty Text Field
                                        ManuelMB Level 3 Level 3 (175 points)
                                        func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool
                                            guard let firstName = productNameTextField.text, !firstName.isEmpty, firstName.count > 0  else {
                                                firstNameAlert.show()
                                                return false
                                            }
                                            guard let lastName = productNameTextField.text, !lastName.isEmpty, lastName.count > 0  else {
                                                lastNameAlert.show()
                                                return false
                                            }
                                        
                                            guard let email = productNameTextField.text, !email.isEmpty, email.count > 0  else {
                                                emailAlert.show()
                                                return false
                                            }
                                        
                                            guard let addressLine1 = productNameTextField.text, !addressLine1.isEmpty, addressLine1.count > 0  else {
                                                addressAlert.show()
                                                return false
                                            }
                                            return true
                                        }