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.
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 am trying to use an unwind segue to logout from my app.
Here is my view hierarchy:
MainVC->(show)->ConnectionVC->(show)->HomeTabBarVC->SettingsVC (4th tab of the HomeTabBarVC containing a tableview)
MainVC, ConnectionVC and HomeTabBarVC are in three different Storyboards.
When pressing the "Disconnect" row of SettingsVC, I want to unwind to MainVC.
I already tried to follow this:
What are unwind segues and how do you use them?
and
Unwind segue and nav button items not triggering after tab bar controller added
The unwindToThisViewController function (which I put in MainVC) from the tutorial is triggered but the only thing that happens is going back to the first tab of HomeTabBarVC.
I tried to execute this action in SettingsVC in two ways:
(self.tabBarController! as! HomeTabBarVC).performSegue(withIdentifier: "unwindToMainVC", sender: self)
and
self.performSegue(withIdentifier: "unwindToMainVC", sender: self)
Neither are working...
Any toughts?
You can do this without using unwind segues. Just use popToRootViewController:
navigationController?.popToRootViewController(animated: true)
I found a solution : after seeing that I had the "Presenting view controllers on detached view controllers is discouraged " warning, I created a Delegate to execute the segue in my HomeTabBarVC and it works fine! Thanks everyone for your help!!
I've read several posts on this issue but none of them solved my problem.
I'm coding an app where I have to click on a button ("Prepare") to go to the following ViewController. When the button is clicked, it also passes data between the two view controller.
The problem is, when I click the button, the following ViewController loads twice. Thus, if I want to go back I have to go back through two same ViewController.
I've checked the segue, the class names and files names but nothing fixes it.
I've also created a new project and rewritten all the code from the beginning but in the end, it still doesn't work.
However, I've noticed that the problem showed up when I added the prepare(forSegue:) function and the performSegue function. Without it the ViewController only loads once. But of course, I can't get the data passed between the views without it...
Here is the screenshot of my two view and the code of the two functions :
First view
Second view
// Prepare the segue
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "prepareSegue" {
let timerViewController = segue.destination as! CountdownViewController
timerViewController.timeInterval1 = waitingTime
timerViewController.timeInterval2 = shootingTime
timerViewController.lastSeconds = lastSeconds
timerViewController.currentTimeInterval = waitingTime
}
}
// Prepare the timer when the button is pushed
#IBAction func prepareTimer(_ sender: Any) {
performSegue(withIdentifier: "prepareSegue", sender: self)
}
Probably, when two ViewControllers appear it's because you have:
A segue on Storyboard which start directly from a Button
IBAction attached to the button where you call a performSegue of the same Segue
To fix this problem, you need to create a Segue which start directly from ViewController. After you can use the IBAction and the performSegue
You have added a seague but also an IBAction. If the seague is defined well in InterfaceBuilder it will perform and call your method. The IBAction is the alternative way for connecting an Action to a button. If you use both, you have two actions.
Without the rest of your project to check, one thing it could be is a completion closure which contains the performSegue(...) statement is called twice, so the performSegue statement is literally run twice. How might this happen?
If you have a networking call inside the closure which contains performSegue command, and the networking call has a closure which calls completion(...) twice, then you could get either the segue occuring twice or even recursively!
It's rare this will be the case, or in your instance, but this type of problem can be uncovered by using lots of breakpoints and following the "bouncing ball" to see the completion() calls occuring more than once.
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.