In my Xcode interface builder, I'm not finding unwind-segue exit action. what is the problem in this case?
The list of segues available in that Exit panel is populated based on the unwind segues you have defined as #IBActions in your other view controllers, for example:
#IBAction func unwindFromExampleViewController(segue: UIStoryboardSegue) {
}
This tells iOS that the UIViewController with this action in it (let's call it ViewControllerA) is ready to handle the unwind from the UIViewController in your screenshot (ViewControllerB).
Have you implemented such an action in another VC yet? Once you've have that in place (in one or more VCs), you'll be able select 'unwindFromExampleViewController' from the list of Exit options for ViewControllerB.
FYI: you can define the same unwind action in multiple VCs if you need to; iOS will pick the 'nearest' one to unwind to when it gets called.
You can find more details on using unwind segues in this question here.
Related
I've followed the instructions here and here which suggest that I should be able to create an unwind/edit segue even when using a storyboard reference.
The flow is quite simple:
PhotoDetailScene has a storyboard reference to EditHistoryScene and a tap gesture to trigger the segue, then I have a close button on EditHistoryScene that unwinds back to PhotoDetailScene. The present works fine (the custom 'show' segue opens the EditHistoryScene), and if I use a dismiss() call it dismisses fine. But unwinding with the segue identifier always fails with:
EditHistoryScene has no segue with identifier 'UnwindEditHistorySegue'
In my EditHistoryScene close button action, I have:
func closeButtonPressed(_ sender: Any)
performSegue(withIdentifier: "UnwindEditHistorySegue", sender: self)
}
And in my PhotoDetailScene, I have added:
#IBAction func unwindToPhotoDetailScene(_ unwindSegue: UIStoryboardSegue) {
print("It works!")
}
And here's how I've set it up in IB, with the unwindToPhotoDetailScene() method connected to the storyboard reference (since that's the only way IB would let me ctrl+link the outlet):
Presenting segue:
Unwind segue properties (and segue name)
Storyboard reference correctly set for destination storyboard:
Storyboard reference's exit point connected back to PhotoDetailScene:
EditHistoryScene storyboard instance appears to not be connected to the #IBOutlet?
My best guess is that it's failing because this is a storyboard reference, and the unwind segue is defined on the reference, not the actual storyboard instance. But I can't figure out how to attach the EditHistoryScene's exit point to the PhotoDetailScene directly.
You don't need to create any segues to the reference itself.
Once your second storyboard contains a reference to the first storyboard, any unwind functions defined in the first storyboard are available.
You create exit segues by dragging from the exit trigger to the exit icon in the view controller scene.
If you want to trigger the unwind from your "close" button, simply ctrl-drag from the close button to the "exit" icon at the top of its view controller and you will see unwindToPhotoDetailScene as an option.
You only need to give the segue an identifier if you want to trigger it programatically.
For example, you might want an action handler function on the close button that checks to see if there are unsaved changes. If there are, prompt the user to confirm that they will lose their changes (or to save or whatever). Once they are happy to proceed you can the invoke the unwind.
To set this up, ctrl-drag from the view controller object to its own exit icon. Create the unwind segue and give it an identifier.
I'm trying to get an unwind segue working (in Swift) and have read through all the "unwind segue not working" posts I could find but haven't yet found whatever it is I'm doing wrong. So.
I have a UISplitViewController with a UITableViewController as my left-hand menu and two UINavigationController+UITableViewController detail views that I'm switching between. Segue-based navigation from my left-hand menu works fine. It's when I want to programmatically unwind that things do not.
I've created an #IBAction function in my first view controller, the one I want to unwind to, like this:
#IBAction func unwindToDocuments(_ segue: UIStoryboardSegue) {
}
(My first view controller is my "Documents" view.)
Then, in the second view controller, I connect an unwind segue to the exit node with identifier unwindSegueToDocuments and action unwindToDocumentsWithSegue:.
It's my understanding that should be all I need to do. However, when I try:
self.performSegue(withIdentifier: "unwindSegueToDocuments", sender: self)
it doesn't do anything. It stays in my second view controller as the detail view.
I'm using self.performSegue there because I'm in a closure. It's some network work so it's being done in a DispatchQueue.async() background queue. However, the performSegue call is in a nested DispatchQueue.main.async() block at the end. (Or, rather, I've tried it both/all ways, and still can't get it to unwind.)
Nothing helpful appears in the console.
My app's navigation flow looks a bit like this:
UINavigationController - MasterViewController > DetailViewController > InfoViewController
MasterViewController contains the following method:
#IBAction func unwindToMaster(with segue: UIStoryboardSegue) {}
In DetailViewController, there is a similar method:
#IBAction func unwindToDetail(with segue: UIStoryboardSegue) {}
I use these methods, along with UIButtons, to allow the user to advance forward and back through the navigation hierarchy. In interface builder, I see the method under DetailViewController when I right click on "Exit" in InfoViewController, but when I right click on "Exit" in DetailViewController, no other unwind segues are listed.
I have consulted multiple online sources (Ray Wenderlich, relevant StackOverflow questions) instructing the correct way to produce unwind segues in interface builder, but none of these have helped solve the issue. Right now, I need help figuring out what the problem is in the first place. As development usually goes, it's probably something staring me square in the face.
I am running Xcode 8.1 using Swift 3. Thank you.
To re-iterate: not only an Action for a Storyboard Unwind Segue has to be placed in the same source file as class definition for an unwind-to (destination) View Controller (e.g., #IBAction func prepareForUnwind(segue: UIStoryboardSegue), detected as prepareForUnwind[With]Segue in a "Presenting Segues" list), but also that View Controller cannot have ANY extensions in ANY secondary source files. You have to merge class definition and all extensions into a single source file.
(As of Xcode 8.2.1.)
In my case, I had a complicated inheritance in my view controller and it was a reason why Interface Builder did not see my unwind. So this workaround works for me well:
Go to YouCollViewController.swift file and delete all classes, protocols, generics, etc. your view controller implements in view controller's declaration
Inherit your view controller from UIViewController
Go to the storyboard and connect your action with the unwind, it should appear in unwinds list
Go back to YouCollViewController.swift file and discard all the changes
I consulted Apple's Developer Library (specifically the page "Using Unwind Segues"). There, the example definition of an unwind action is:
#IBAction func unwindToMainMenu(sender: UIStoryboardSegue) {
let sourceViewController = sender.sourceViewController
// Pull any data from the view controller which initiated the unwind segue.
}
Applying this example in my code, I changed my unwind action declarations to:
#IBAction func unwindToMaster(sender: UIStoryboardSegue) {
print("Unwinded to master.")
}
and
#IBAction func unwindToDetail(sender: UIStoryboardSegue) {
print("Unwinded to detail.")
}
I also made sure that each method was contained within the same file as MasterViewController's class declaration. After further testing, I found that all extensions of MasterViewController had to exist in the same file for interface builder to find and recognize the unwind segue.
Now, in storyboard, the exit menu shows both unwind segues. My conclusion is that by fiddling around with where the methods are placed and how they are declared, a configuration that interface builder can recognize will be found. I hope it will be less touchy in the future, as my current method organization is very long and difficult to navigate.
Because none of these answers helped me and I didn't want to mess around with my code that much. Here another solution you can give a try.
Starting from the point where you have already added the unwind function to your MasterViewController.
First I have gone ahead and added a new ViewController to my storyboard as well as a new Cocoa Touch Class File of type UIViewController and connected it with my Storyboard one (I called it the HelperViewController).
Then you can add the same unwind function, you already have inside your MasterVC to your newly created HelperVC.
#IBAction func unwindToMaster(with segue: UIStoryboardSegue) {}
Now connect the Helper to your DetailVC. Your Storyboard should look somewhat like mine. You should get the same option as me if you ctrl + drag and drop to the exit of your DetailVC. When the connection has been established and you hover over the newly created segue both the Master and the HelperVC should be highlighted. Now you can delete the HelperVC again and everything should work as expected.
I hope that helped!
With swift 4 XCode 9.2 I found that you need to drag the reference from the yellow icon at the top of the viewController to the "Exit" reference of the target viewController in the left details panel. Hope this helps!
Sometimes XCode restart makes the actions appear.
I ran into an issue where I had the following setup, but was unable to get an unwind segue to work.
The storyboards were created several months ago, and were refactored from an original main storyboard to split them out into individual ones, with each storyboard having a single view controller.
The storyboards:
MainMenu.storyboard (Contains the navigation controller)
SubMenu.storyboard (Contains the segue that sends the user to the destination storyboard)
Destination.storyboard (Should contain unwind segue)
In the SubMenu viewcontroller, I have the following unwind segue:
#IBAction func unwindToSubMenu(segue: UIStoryboardSegue) {}
I then place a bar button item on the navigation item for the destination view controller. Attempting to link the bar button item to the exit icon on the Destination.storyboard file does not result in the unwindToSubMenu segue appearing.
Also, right clicking on the exit icon results in an empty field.
I did attempt to move the Destination.storyboard contents back to the SubMenu.storyboard to see if it had something to do with the reference links, but this was unsuccessful.
Updated with a better answer.
I ran into this problem again using the latest version of XCode (8.2.1) where a properly configured segue was not appearing.
To make sure I was not insane, I first created a small sample project where I only lifted the relevant code, and was able to confirm that it was set up properly.
With that out of the way, I found a better solution to this issue by creating a garbage storyboard & associated view controller.
The view controller only contained this code:
class GarbageViewController: UIViewController {
#IBAction func unwind(_ segue: UIStoryboardSegue) { }
}
This was then set as the view controller for the garbage storyboard.
I then clicked on the exit outlet in the garbage storyboard file to confirm that the unwind method defined above appeared. Once it appeared, the unwind segue I wanted suddenly became available as well.
In my story board I have VC1>VC2>VC2>VC4
In order to go right back to VC1 from VC4 I have setup the function:
#IBAction func unwindToVcOne(segue: UIStoryboardSegue) {
}
Then adding that to my segue from the storyboard.
Everything works fine except that it shows up as an empty circle in my editor as its not connected:
It works, so is this something that I can ignore?
As far as I know the circle next to an unwind method always shows as empty as there isn't a fixed binding between the storyboard scene and the method the way that there is with an action method.
The IBAction lets Interface Builder know that there is a method it should be interested in; the method signature indicates that it is an unwind segue method.
The actual unwind method that is called is determined at runtime as describe in this Apple Technical Note.