317

Using storyboard this is very easy. You just drag the action to "Exit". But how should I call it from my code?

ЯegDwight
  • 23,615
  • 10
  • 43
  • 51
tadasz
  • 4,288
  • 5
  • 24
  • 33
  • 34
    I find this a valid question – I had it myself. You can perform an unwind segue programmatically by 1. creating a manual segue (ctrl-drag from File’s Owner to Exit), 2. giving it a name in IB, then 3. doing a normal -performSegueWithIdentifier:sender: in your code. – Yang Meyer Oct 03 '12 at 15:11
  • 6
    Should not have been closed IMO. The users that voted to close this question sure don't seem to have an Obj-C / Cocoa Touch background. – LJ Wilson Oct 23 '12 at 14:46
  • Yang: How do you give it a name? – sarfata Oct 31 '12 at 01:51
  • I just use [self dismissViewControllerAnimated:YES completion:nil]; to exit programmatically. I don't know it's a right way or not. – tangqiaoboy Nov 03 '12 at 10:00
  • DismissViewControllerAnimated:Completion: should be sent to the controller (presenting controller) that present the one to be dismissed (the presented controller). If the msg is sent to the one to be dismissed, it's simply forwarded to the presenting controller. But the presenting controller has to know it's dismissed. So the presented controller either notify it via a delegate (in iOS5) or via an unwind segue (available in iOS6). – huggie Nov 21 '12 at 13:06
  • 1
    sarfata: You first create a "manual unwind segue" by ctrl-drag from viewcontroller to "Exit". Then you can find the segue in the Document Outline. – huggie Nov 21 '12 at 13:11
  • Great answer to this question is given [here](http://stackoverflow.com/a/15839298/1132951) May this will help you some more :) – The iOSDev Nov 19 '13 at 05:53
  • I don't get this when it is a segue, it means there is a storyboard, and it is no longer "Programmtically". – Mohamad Apr 04 '19 at 01:59

10 Answers10

289
  1. Create a manual segue (ctrl-drag from File’s Owner to Exit),
  2. Choose it in the Left Controller Menu below green EXIT button.

Choose it in the Left Controller Menu below green EXIT button

Insert Name of Segue to unwind.

Then,- (void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender. with your segue identify.

Vadim
  • 2,914
  • 1
  • 11
  • 6
  • 26
    1) "File's Owner" -- isn't that old terminology? It worked for me to control drag from the view controller to its Exit icon. 2) Though it ought to be obvious, Xcode is looking for a declaration in the Interface of the IBAction which takes a UIStoryboardSegue argument; the WWDC 2012 session 407 talk didn't mention that and didn't paste that code in. Without it, my Exit icon wouldn't go active when control-dragging to it. 3) It's pretty cool that at the end of your big red arrow, in the Action field, you can hit the "go there" arrow! – tobinjim Dec 09 '12 at 06:59
  • 73
    For anyone who, like me, *still* has trouble with implementing this answer, I put together a more thorough walkthrough and example in this repo: https://github.com/bradley/iOSUnwindSegueProgramatically (Not trying to advertise myself, I just banged my head against the wall for hours on this and seeing a working setup helps me.) – bradleygriffith May 24 '13 at 19:36
  • 3
    @bradleygriffith You are amazingly super awesome. Thanks for the great walkthrough ! – Eli_Rozen Dec 21 '13 at 00:28
  • I tried this for hours, even digging through bradleygriffith's example, and it never worked for me. As far as I can tell, everything is set up the same as the example project, but I would always get SIGABRT - receiver has no segue with identifier. In the end, calling [self dismissViewControllerAnimated:TRUE completion:nil]; worked and was much easier to do (no messing with the storyboard required). See this - http://stackoverflow.com/questions/14957774/ios-6-programmatically-triggering-unwind-segue-does-nothing – user1021430 Feb 13 '14 at 01:13
  • 7
    @bradleygriffith I wish you'd made this an answer so I could mark that up too! Your unique contribution was establishing *which view controller gets what code*. Couldn't find that anywhere. Thanks! – Aaron Vegh Sep 08 '14 at 15:37
  • 3
    The key, for anyone still stumped on this, is that the IBACTION needs to be in the view controller you are returning to, not the one you're currently in. @bradleygriffith spells this out on GitHub, but I haven't seen that mentioned anywhere else. That part is critical. – Axeva Dec 04 '14 at 15:23
  • [This](http://stackoverflow.com/a/13090209/1789384) this is useful for passing information to the unwind action (`IBACTION`). – Drux Feb 10 '15 at 11:04
  • @bradleygriffith Thank you so much for that. The thing I should bang my head is that I need to define that unwind method in view controller class that I need to *unwind to*, not the view controller that we return from. – haxpor Sep 06 '15 at 06:55
  • Should be: "2. Choose it on the document outline menu below the (orange) EXIT button. – John Doe Oct 14 '15 at 01:38
174

Here's a complete answer with Objective C and Swift:

1) Create an IBAction unwind segue in your destination view controller (where you want to segue to). Anywhere in the implementation file.

// Objective C

    - (IBAction)unwindToContainerVC:(UIStoryboardSegue *)segue {

    }

// Swift

 @IBAction func unwindToContainerVC(segue: UIStoryboardSegue) {

    }

2) On the source view controller (the controller you're segueing from), ⌃ + drag from "Name of activity" to exit. You should see the unwind segue created in step 1 in the popup. (If you don't see it, review step one). Pick unwindToContainerVC: from the popup, or whatever you named your method to connect your source controller to the unwind IBAction.

enter image description here

3) Select the segue in the source view controller's document outline of the storyboard (it will be listed near the bottom), and give it an identifier.

enter image description here

4) Call the unwind segue using this method from source view controller, substituting your unwind segue name.

// Objective C

[self performSegueWithIdentifier:@"unwindToContainerVC" sender:self];

// Swift

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

NB. Use the sourceViewController property of the segue parameter on the unwind method to access any exposed properties on the source controller. Also, notice that the framework handles dismissing the source controller. If you'd like to confirm this add a dealloc method to the source controller with a log message that should fire once it has been killed. If dealloc doesn't fire you may have a retain cycle.

smileBot
  • 18,797
  • 7
  • 60
  • 62
  • 2
    My program does not work, not even called `(IBAction)unwindToContainerVC:(UIStoryboardSegue *)segue` – xhg Feb 09 '15 at 07:03
  • 2
    this solution does not work when the view controller, you are unwinding to, does only exist in your storyboard, aka does not have a custom in code implementation – mnl Apr 02 '15 at 14:00
  • @mnl not sure exactly what you're saying, but it works with storyboard scenes or nibs. If you're creating a viewcontroller scene in code then you wouldn't use any methods that "return" IB in their name, which is really void anyway since these serve the purpose of communicating between code and IB. Does that address your comment? – smileBot Apr 02 '15 at 14:19
  • 1
    Your picture showing the `ctrl+drag` from `ViewController` to `Exit` was incredibly helpful. Thanks! – kbpontius Aug 13 '15 at 23:26
  • For Swift 4.2 use: self.performSegue(withIdentifier: "unwindToVC", sender: self) – Reefwing Jan 08 '19 at 06:48
86

bradleygriffith's answer was great. I took step 10 and made a screenshot for simplification. This is a screenshot in Xcode 6.

  1. Control-drag from the orange icon to the red Exit icon to create an unwind without any actions/buttons in the view.

enter image description here

  1. Then select the unwind segue in the sidebar:

enter image description here

  1. Set a Segue Identifier string:

enter image description here

  1. Access that identifier from code:
[self performSegueWithIdentifier:@"unwindIdentifier" sender:self];
pkamb
  • 26,648
  • 20
  • 124
  • 157
Dean
  • 6,678
  • 10
  • 49
  • 83
15

I used [self dismissViewControllerAnimated: YES completion: nil]; which will return you to the calling ViewController.

Jack
  • 10,783
  • 12
  • 46
  • 65
Larry Gibson
  • 199
  • 4
  • 6
    Larry, that's a perfectly valid approach if you are wanting to return to the previous view controller, i.e. the one that presented the one you are now exiting. The question came up because new in Xcode 4.5 is an ability to "unwind" from one view controller somewhere in the presentation order to a much earlier view controller. See WWDC 2012 session 407 for details. – tobinjim Dec 09 '12 at 06:55
11

Quoting text from Apple's Technical Note on Unwind Segue: To add an unwind segue that will only be triggered programmatically, control+drag from the scene's view controller icon to its exit icon, then select an unwind action for the new segue from the popup menu.

Link to Technical Note

Vishal Chaudhry
  • 2,624
  • 1
  • 20
  • 8
6

Vishal Chaudhry's answer above worked for me. I would also add that in order to manually trigger the seque using:

[self performSegueWithIdentifier:@"mySegueName" sender:self];

from within the ViewController you must also select the unwind segue under the ViewController's Scene in the storyboard and in the properties view on the RHS ensure that the Indentifier field contains the namer you're referring to in the code ("mySegueName" in the example above).

If you omit this step, the line above will throw an exception that the seque name is not known.

Jason Crocker
  • 431
  • 4
  • 7
3

Backwards compatible solution that will work for versions prior to ios6, for those interested:

- (void)unwindToViewControllerOfClass:(Class)vcClass animated:(BOOL)animated {

    for (int i=self.navigationController.viewControllers.count - 1; i >= 0; i--) {
        UIViewController *vc = [self.navigationController.viewControllers objectAtIndex:i];
        if ([vc isKindOfClass:vcClass]) {
            [self.navigationController popToViewController:vc animated:animated];
            return;
        }
    }
}
Joel Teply
  • 3,013
  • 1
  • 27
  • 20
3

SWIFT 4:

1. Create an @IBAction with segue inside controller you want to unwind to:

    @IBAction func unwindToVC(segue: UIStoryboardSegue) {

    }

2. In the storyboard, from the controller you want to segue (unwind) from ctrl+drag from the controller sign to exit sign and choose method you created earlier:

enter image description here

3. Now you can notice that in document outline you have new line with title "Unwind segue....". Now you should click on this line and open attribute inspector to set identifier (in my case unwindSegueIdentifier).

enter image description here

4. You're almost done! Now you need to open view controller you wish to unwind from and create some method that will perform segue. For example you can add button, connect it with code with @IBAction, after that inside this IBAction add perfromSegue(withIdentifier:sender:) method:

     @IBAction func unwindToSomeVCWithSegue(_ sender: UIButton) {
         performSegue(withIdentifier: "unwindSegueIdentifier", sender: nil)
     }

So that is all you have to do!

Chad Parker
  • 121
  • 2
  • 5
wm.p1us
  • 1,863
  • 23
  • 31
2

Swift 4.2, Xcode 10+

For those wondering how to do this with VCs not set up via the storyboard (those coming to this question from searching "programmatically" + "unwind segue").

Given that you cannot set up an unwind segue programatically, the simplest solely programmatic solution is to call:

navigationController?.popToRootViewController(animated: true)

which will pop all view controllers on the stack back to your root view controller.


To pop just the topmost view controller from the navigation stack, use:

navigationController?.popViewController(animated: true)

10623169
  • 726
  • 1
  • 8
  • 20
0

FYI: In order for @Vadim's answer to work with a manual unwind seque action called from within a View Controller you must place the command:

[self performSegueWithIdentifier:(NSString*) identifier sender:(id) sender];

inside of the overriden class method viewDidAppear like so:

-(void) viewDidAppear:(BOOL) animated
{
    [super viewDidAppear: animated];

    [self performSegueWithIdentifier:@"SomeSegueIdentifier" sender:self];
}

If you put it in other ViewController methods like viewDidLoad or viewWillAppear it will be ignored.

John Verco
  • 1,254
  • 8
  • 6
  • 3
    Definitely wrong. Call performSegueWithIdentifier from wherever you want. – smileBot Oct 07 '14 at 18:11
  • Wouldn't this just perform unwind segue as soon as the view loads? Rather than performing when YOU want to, for example after pushing a button. – Pahnev Dec 19 '14 at 18:20
  • @Pahnev yes it would. I don't know how this answer got any upvotes. Calling `performSegueWithIdentfier` does exactly that: performing the segue from one ViewController to another – ezcoding Sep 28 '16 at 12:36
  • Completely wrong. It would just rewind immediately on launch. – Lee Probert Nov 08 '16 at 14:37