5

I have an app set up where the user can log in and log out (this is handled via a Parse-server hosted by heroku, with a Parse framework).

To log in, the user inputs credentials, and if the server verifies them a segue moves them to another viewcontroller. Signing out signs the user out of the app and segues that back to the login screen. These work fine.

If the initial login credentials are incorrect, an alert is displayed prompting the user to retry and the user is not logged-in (obviously) and is left on the login screen.

A problem arises, though, if the user is signed-in, logs out, and then inputs incorrect credentials (in this order, with no closure of the simulator). The incorrect credentials bring up the prompting alert; hitting "OK" closes the alert, the user is not logged in, but the view is segued to the logout screen (where the sign out button is... this should only be accessible to logged in users). No segue segue exists (either coded or on the story board) that moves the user from the login directly to the logout screen.

No actions work since many require the users ID, and there is none since none is logged in. I have no idea why the incorrect login would move the VC's in that way since no segue exists that can do that. There is one that does that movement in reverse (when logging out), but none in that direction.

Anybody have any ideas? Below is the relevant logging-in code.

@IBAction func signInTapped(_ sender: UIButton) {
        UIApplication.shared.beginIgnoringInteractionEvents()

        PFUser.logInWithUsername(inBackground: userNameTextField.text!, password: passwordTextField.text!, block: { (user, error) in
            if user != nil{

                self.performSegue(withIdentifier: "signInSegue", sender: self)//if the sign in works    
            } else{

                if let errorString = (error! as NSError).userInfo["error"] as? String{

                    let errorMessage = errorString

                    self.displayAlert("Failed login", message: errorMessage)//this is the code run when the login fails, yet it somehow can sometimes segue to the other viewcontroller
                }   
            }
        })
}

Here is the step by step schematic of what is going on. The user starts at the login page and inputs his/her credentials This segues the user (now logged on) to a <code>tabbarViewController</code> They then navigate to another tab and there is a sign out button Pressing the sign out button causes an alert to appear, hitting yes segues the user (now logged out) to the original screen The user is now at the login screen. Inputting the wrong info brings up an alert The alert appears. Hitting yes closes the alert is supposed to leave the user on the login screen. However, there is an immediate segue to the logout screen again... this is neither coded nor manually set in the storyboard

  1. The user starts at the login page and inputs his/her credentials
  2. This segues the user (now logged on) to a tabbarViewController
  3. They then navigate to another tab and there is a sign out button
  4. Pressing the sign out button causes an alert to appear, hitting yes segues the user (now logged out) to the original screen
  5. The user is now at the login screen. Inputting the wrong info brings up an alert
  6. The alert appears. Hitting yes closes the alert is supposed to leave the user on the login screen. However, there is an immediate segue to the logout screen again... this is neither coded nor manually set in the storyboard

Random things I think might be relevant: There is an initial segue, called on the viewDidAppear of the first VC (the login screen) upon turning on the app. It checks if there is a user logged in, via

if PFUser.current().username? != nil {
      //perform segue
}

This segue brings them to the map section on the tab bar (NOT the sign out page as is happening with the issue).

EDIT: Upon the "segue" to the logout screen occurring, the login screen drops (like literally, falls downward on the screen until its not seen and the logout screen is the then viewable which is not the way any segues in the app function). Also, only the viewDidAppear code is called when this transition occurs, NOT the viewDidLoad code.

EDIT 2: I think the issue has to do with the view hierarchy. Here is the code for the login function:

PFUser.logInWithUsername(inBackground: userNameTextField.text!, password: passwordTextField.text!, block: { (user, error) in

            if user?.username != nil{ 
                self.performSegue(withIdentifier: "signInSegue", sender: self) 
            } else{ //if everything in this code block is commented, the issue does not occur
                if let errorString = (error! as NSError).userInfo["error"] as? String{
                    let errorMessage = errorString
                    self.displayAlert("Failed login", message: errorMessage)
                }  
            }
        })

If I comment out everything in the else part of the if statement, the issue does not occur. What I believe is happening is that the alert is displayed, and hitting "ok" closes the alert and sends the app back to the topmost (maybe I'm wrong with what I'm calling it) viewController, which is somehow the signout VC. I think a good way to fix it would be to add like a self.present(homescreenVC) or something like this to the else code, but I do not know how to do this.

Runeaway3
  • 1,439
  • 1
  • 17
  • 43
  • Is the the presenting controller the one you think it is? And I assume you have no unwind seques? – clearlight Jan 04 '17 at 07:52
  • In your write up, you mention the user logging out then entering credentials. That implies some sort of transition from the logged-out state to the logging-in functionality. How do they get from the logged-out screen to the logging-in screen? – clearlight Jan 04 '17 at 07:58
  • It looks like you're in the sign-in section via an `IBAction` (tap), from the logged out state...? I don't know what `PFUser.loginWithUsername()` does, but there seems to be no obvious segue that you've created since login fails. I don't know what your `displayAlert()` method does when it completes. Can you show that too? – clearlight Jan 04 '17 at 08:04
  • @HotAppleCyber 1) I do not know what an unwind segue is, so I do not think I have any implemented 2) There is a logout function called. Once it has logged the user out from the system, a `performSegue` moves them from the log out screen to the login in screen 3) The `PFUser.loginWithUsername()` is what logs the user into the system... it verifies the users credentials with those in the DB... if they are correct, the user is logged in. And there isn't any segue when the log in fails. The alert is displayed, the user hits ok, and is still at the login screen (when it functions correctly) – Runeaway3 Jan 04 '17 at 18:12
  • @HotAppleCyber logging in basically just allows the app to call `PFUser.Current()` which can call object properties from the user's section in the DB. When the `displayAlert()` is called, it just shows a message box saying the login failed. The user can only hit "ok" and it closes the alert, and they are left on the login screen. However, if that specific series of events happened (logging in, logging out, putting in wrong credentials), after hitting "ok" the user is moved to another VC (the logging out VC) despite no segue being called – Runeaway3 Jan 04 '17 at 18:18
  • Right, so - they log out, which involves some sort of segue to the log out code, right? Now they're logging in, but that's not the result of a segue, but rather an IBAction, and if login fails, the intended signInSegue is not taken, but rather a dialog pops up and when it exits it leaves you back at the logout controller you were at prior to the IBAction that got you into the code where you popped up the dialog. Seems to think that's the right thing to do. Not sure what the right solution is yet, but what comes to mind is... – clearlight Jan 04 '17 at 18:23
  • Maybe in your IBAction you can segue to the login screen rather than process the sign in as an action. Or somehow update the segue stack or presenter so that by the time you pop up the dialog, you know that when the dialog exits it takes it to where you really are/want to go. Could involve some segue/controller re-structuring, or merely hacking the segue stack. Not sure, as I haven't seen a lot of your code. – clearlight Jan 04 '17 at 18:25
  • The logout does come from an IBAction as well. There is a button they click to click which signs them out. The button displays an alert, and hitting "yes" calls the logout function `PFUser.logout` and then performs a segue to the login screen. I can take a look at your suggestion, but there is a function called as a result of the IBAction and then a segue to the login screen when signing out. – Runeaway3 Jan 04 '17 at 19:13
  • It's too difficult to help you with so much in the abstract without you showing more of what you're doing in code and/or a very clear, perhaps diagrammatic illustration of the states/flows involved that brought you from which state/controller, to which state/controller etc... – clearlight Jan 04 '17 at 20:37
  • http://stackoverflow.com/a/15839298/2079103 – clearlight Jan 04 '17 at 20:37
  • https://www.andrewcbancroft.com/2015/12/18/working-with-unwind-segues-programmatically-in-swift/ – clearlight Jan 04 '17 at 20:37
  • http://stackoverflow.com/questions/9407571/to-stop-segue-and-show-alert – clearlight Jan 04 '17 at 20:37
  • @Hot Apple Cyber, i edited the question to hopefully be more clear. Does this help you diagnose the problem better? I'm still not sure what the issue is – Runeaway3 Jan 05 '17 at 23:50
  • 1
    I've had to solve weird problems with segues in my own code before. It can be a real challenge and hassle. Read up on some of the stuff I posted, look into unwind and try to get familiar with how the underlying mechanisms of segues work and that should help you diagnose it and resolve it. Might take some time. That's how it goes. – clearlight Jan 06 '17 at 00:49
  • Can you post the code of `self.displayAlert("Failed login", message: errorMessage)` and the code that handles the actions of that alert view? – Mihai Fratu Jan 13 '17 at 07:27
  • @ Mihai Fratu, that's all is in there. I think I forgot to actually include the action of the alert view. That's all the code that handles it – Runeaway3 Jan 14 '17 at 01:43

1 Answers1

0
@IBAction func signInTapped(_ sender: UIButton) {
    UIApplication.shared.beginIgnoringInteractionEvents()

    PFUser.logInWithUsername(inBackground: userNameTextField.text!, password: passwordTextField.text!, block: { (user, error) in
        if error != nil {
             if let errorString = (error! as NSError).userInfo["error"] as? String{

                let errorMessage = errorString

                self.displayAlert("Failed login", message: errorMessage)
               }
        } 
        else {
            self.performSegue(withIdentifier: "signInSegue", sender: self)

            }   
        })
    }