(Swift) Unwind segue when multiple view controllers lead to same view?
Asked Answered
L

3

13

I am trying to code a hangman game and am having trouble with unwind segues. I have multiple view controllers that all ultimately lead to the same view, where the user plays the actual hangman. However, depending on the presenting controller, I want the game to be in different "modes" (ie: multiplayer, single player, etc.). I am trying to add a play again button that unwinds to the previous view controller, but am unsure how to unwind when there are multiple paths the user could have taken to get to this view.

In other words, my app kind of goes:

A -> B -> C or

A -> D -> C where C can (ideally) unwind to D or B.

I was wondering what the best way to implement this is? Should I just embed all my view controllers in navigation controllers? Or is there a way to present a certain view controller based on a certain condition? Thank you for any help!

Latterly answered 24/7, 2015 at 21:15 Comment(0)
L
11

The unwind segue process will generally determine the previous UIViewController instance automatically. The exact process is described in this Tech Note from Apple, but in summary:

Starting from the view controller that initiated the unwind segue the search order is as follows:

  1. The next view controller in the responder chain is sent a viewControllerForUnwindSegueAction:fromViewController:withSender: message. For a view controller presented modally, this will be the view controller that called presentViewController:animated:completion:. Otherwise, the parentViewController.

    The default implementation searches the receiver's childViewControllers array for a view controller that wants to handle the unwind action. If none of the receiver's child view controllers want to handle the unwind action, the receiver checks whether it wants to handle the unwind action and returns self if it does. In both cases, the canPerformUnwindSegueAction:fromViewController:withSender: method is used to determine if a given view controller wants to handle the unwind action.

  2. If no view controller is returned from viewControllerForUnwindSegueAction:fromViewController:withSender: in step one, the search repeats from the next view controller in the responder chain.

So, the precise process will depend on how you presented view controller C - for example, via a modal presentation segue or a push segue on a UINavigationController but as long as both B and D implement the unwind action you should be good.

Linea answered 24/7, 2015 at 22:26 Comment(0)
B
20

If you have any custom logic and want to invoke the unwind segue programmatically to different view controllers, here is how:

  1. Add unwindFromCViewController to both BViewController and DBViewController:

    BViewController.swift

    class BViewController : UIViewController {
        @IBAction func unwindFromCViewController(segue:UIStoryboardSegue) {
        }
    }
    

    DViewController.swift

    class DViewController : UIViewController {
        @IBAction func unwindFromCViewController(segue:UIStoryboardSegue) {
        }
    }
    
  2. In your storyboard, create this segue and give it a identifier, and link it to the action you defined above unwindFromCViewController:

        enter image description here

        enter image description here

  1. Invoke the unwind segue from code:

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

With that, you can unwind to a previous view regardless where it is coming from.

Bush answered 20/9, 2016 at 19:16 Comment(1)
Hi, the segue is not created for view controllers presented modally. Don't know why. Weird.Grout
L
11

The unwind segue process will generally determine the previous UIViewController instance automatically. The exact process is described in this Tech Note from Apple, but in summary:

Starting from the view controller that initiated the unwind segue the search order is as follows:

  1. The next view controller in the responder chain is sent a viewControllerForUnwindSegueAction:fromViewController:withSender: message. For a view controller presented modally, this will be the view controller that called presentViewController:animated:completion:. Otherwise, the parentViewController.

    The default implementation searches the receiver's childViewControllers array for a view controller that wants to handle the unwind action. If none of the receiver's child view controllers want to handle the unwind action, the receiver checks whether it wants to handle the unwind action and returns self if it does. In both cases, the canPerformUnwindSegueAction:fromViewController:withSender: method is used to determine if a given view controller wants to handle the unwind action.

  2. If no view controller is returned from viewControllerForUnwindSegueAction:fromViewController:withSender: in step one, the search repeats from the next view controller in the responder chain.

So, the precise process will depend on how you presented view controller C - for example, via a modal presentation segue or a push segue on a UINavigationController but as long as both B and D implement the unwind action you should be good.

Linea answered 24/7, 2015 at 22:26 Comment(0)
P
5

I would simply call in code popViewController:animated to go to the presenting controller if you pushed it on the navigation stack, or dismissViewController:animated if it was presented modally.

Pineal answered 24/7, 2015 at 21:36 Comment(1)
@Latterly there are two ways to show a new view controller on top of a current view controller on iOS, name, "push" and "present". So "presented modally" here is for the 2nd case.Bush

© 2022 - 2024 — McMap. All rights reserved.