ChatGPT解决这个技术问题 Extra ChatGPT

How to perform Unwind segue programmatically?

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

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.
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.
Yang: How do you give it a name?
I just use [self dismissViewControllerAnimated:YES completion:nil]; to exit programmatically. I don't know it's a right way or not.
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.

V
Vadim

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

https://i.stack.imgur.com/uWRSG.png

Insert Name of Segue to unwind.

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


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!
For anyone who, like me, still has trouble with implementing this answer, I put together a more thorough walkthrough and example in this repo: 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 You are amazingly super awesome. Thanks for the great walkthrough !
@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!
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.
S
SmileBot

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.

https://i.stack.imgur.com/CJSxx.png

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.

https://i.stack.imgur.com/c3vvp.png

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.


My program does not work, not even called (IBAction)unwindToContainerVC:(UIStoryboardSegue *)segue
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 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?
Your picture showing the ctrl+drag from ViewController to Exit was incredibly helpful. Thanks!
For Swift 4.2 use: self.performSegue(withIdentifier: "unwindToVC", sender: self)
p
pkamb

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

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

https://i.stack.imgur.com/idX9l.png

Then select the unwind segue in the sidebar:

https://i.stack.imgur.com/NBxT5.png

Set a Segue Identifier string:

https://i.stack.imgur.com/OLbL5.png

Access that identifier from code:

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

First of all, the method for unwinding must be included inside the UIViewController. Then your solution will work
and you have to set Identifier to this new segue! Don't forget about it.
Is it possible to create the "exit" connection in the source view controller programmatically?
J
Jack

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


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.
V
Vishal Chaudhry

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


J
Jason Crocker

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.


1
10623169

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)


that's usually more than you want - to pop one back just do: [self.navigationController popViewControllerAnimated:YES];
Indeed, I've added that to my answer - thanks @AndyWeinstein
J
Joel Teply

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;
        }
    }
}

Unwind segues do a lot more than popping back to a certain class in a navigation controller stack.
C
Chad Parker

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:

https://i.stack.imgur.com/GFK4L.png

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).

https://i.stack.imgur.com/edUhH.png

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!


Is it possible to create the "exit" connection in the source view controller programmatically?
J
John Verco

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.


Definitely wrong. Call performSegueWithIdentifier from wherever you want.
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 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
Completely wrong. It would just rewind immediately on launch.