3
votes

My Swift segue is not working at all and isn't throwing any errors. The breakpoint shows me that the app lands on this line but nothing happens:

self.performSegueWithIdentifier("SignupSegue", sender: self)

The code block is a login form with Facebook:

if let accessToken: FBSDKAccessToken = FBSDKAccessToken.currentAccessToken() {
    PFFacebookUtils.logInInBackgroundWithAccessToken(result.token, block: {
        (user: PFUser ? , error : NSError ? ) - > Void in
        if user!.isNew {
            self.performSegueWithIdentifier("SignupSegue", sender: self)
        } else {
            self.navigateToInGame(true)
        }
    })
}

Here's the segue function it should call, but doesn't even get to it:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
    {
        if (segue.identifier == "SignupSegue") {
            let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let vc = storyboard.instantiateViewControllerWithIdentifier("SignUpViewController") 
            self.showViewController(vc, sender: self)
        }
    }

Any ideas?

6
I just wanna clear that why do you need to show the viewController after setting segue in storyboard? You might not set the segue with the identifier "SignupSegue". So please double check on that. Correct me if am wrong. - Boopathy
OK, I understand. I commented out the "showViewController" line (I got this from a Google search). I'm just looking to establish a segue from one storyboard to another. Still getting the error after commenting that out. Thanks! - winston

6 Answers

3
votes

Generally, any UI updating has to be in main thread. I think the block for PFFacebookUtils.logInInBackgroundWithAccessToken is still in the background state in above situation. Maybe trigger the showViewController in dispatch_async(dispatch_get_main_queue(), {}) and see if there is any difference.

dispatch_async(dispatch_get_main_queue(), {
    let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    let vc = storyboard.instantiateViewControllerWithIdentifier("SignUpViewController")
    self.showViewController(vc, sender: self)
})
2
votes

Ok. I just tried it out. Hope you did all the things regarding StoryBoard Reference. Me too had the same issue with performSegueWithIdentifier.

Example: Let take two storyboard main and signup.

1) In main.storyboard create a storyboard reference. Set the storyboardId in the Storyboard Reference as signup and the referencedId as the storyboardId of the scene(viewController) which is in signup.storyboard. Look at this link for a clear picture Storyboard to Storyboard

2) Set the segue identifier between viewController and Storyboard Reference in main.storyboard

3) Since I faced the same problem with performSegueWithIdentifier, I replaced it with shouldPerformSegueWithIdentifier.

override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
    if(identifier == "segue_identifier"){
       // segue_identifier is the viewController and storyBoard Reference segue identifier.
        print("hello")
    }
    return true;
}

Let me know if you find any issues. It did work for me.

1
votes

Performing a segue leads to present a new view controller.You don't need to and can't create and show view controller in prepareForSegue.It will look like:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
    {
        if (segue.identifier == "SignupSegue") {

            let vc = segue.destinationViewController

        }
    }
0
votes

Swift 3 solved:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if (segue.identifier == "SignupSegue") {
                DispatchQueue.main.async {
                    let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
                    let vc = storyboard.instantiateViewController(withIdentifier: "SignUpViewController")
                    self.show(vc, sender: self) 
                }
          }
    }
0
votes

You can try this ...

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
    {
    if (segue.identifier == "SignupSegue") {
        if let destination = segue.destination as? SignUpViewController {
         ...
        }

    }
}
0
votes

The closest I can get to overcome same problem for myself:

Made trigger var segueLogin : Bool = false with initialised value in the Class.

When PFFacebookUtils gets needed values for segue, change trigger to true:

PFFacebookUtils.logInInBackground(withReadPermissions: permissions) {
            (user: PFUser?, error: Error?) -> Void in
            if let user = user {
                if user.isNew {
                    print("User signed up and logged in through Facebook!")
                    self.segueLogin = true

                } else {
                    print("User logged in through Facebook!")
                    self.segueLogin = true
                }
            } else {
                print("Uh oh. The user cancelled the Facebook login.")
                self.loginCancelledLabel.alpha = 1
            }
        }

Then added code to viewDidAppear class. Realised it starts everytime PFFacebookUtils complete. So it checks if returned value is true and performs segue after successful PFFacebookUtils session:

override func viewDidAppear(_ animated: Bool) {
        if segueLogin == true {
            self.performSegue(withIdentifier: "segueSingup", sender: self)
        }
    }