I am use to performing unwinds to the easy what that is like this:
First set this on the destination view controller:
#IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {}
Finally drag and drop and then pick the wanted unwind:
But till Xcode updates to 8.2.1 if you have the destination view controller with some extensions it doesn't appear on the list (Manual Segue). I didn't update to 8.3 because I'm still using Swift 2.3 so I don't know in further versions this bug is solved.
Instead of having to move all the extensions in the same file, which it will be a chaos find anything there. I am wondering if there is any other way to perform this action without using the storyboard step.
I am currently using navigation controller, maybe popToViewController will do it? I don't know honestly.
Thank you very much for the help.
In the storyboard, give your unwind segue an identifier.
Then, in your code do:
performSegue(withIdentifier: "SegueID", sender: nil)
Source: https://spin.atomicobject.com/2014/12/01/program-ios-unwind-segue/
Related
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.
When trying to connect a Navigation Bar Button to the Exit item of a ViewController in Xcode 6 (not really sure if it's an Xcode 6 problem but worth mentioning as it is in beta) it does not find the Swift function in the custom class.
The function it should be finding:
#IBAction func unwindToList(segue: UIStoryboardSegue) {
}
I made another button on the view just to make sure I could get an IBAction working with Swift and that I was writing it correctly. This works fine:
#IBAction func test(sender: AnyObject) {
NSLog("Test")
}
I have seen this question that seems like the same issue but according to the answers there this should be working.
Xcode 6 is in beta and, of course, Swift is very new, but wanted to see if anyone has come across this before considering it a potential bug.
This is a known issue with Xcode 6:
Unwind segue actions declared in Swift classes are not recognized by Interface Builder
In order to get around it you need to:
Change class MyViewController to #objc(MyViewController) class MyViewController
Create an Objective-C header file with a category for MyViewController that redeclares the segue action.
#interface MyViewController (Workaround)
- (IBAction)unwindToMyViewController: (UIStoryboardSegue *)segue;
#end
In the storyboard, select the instance of MyViewController, clear its custom class, then
set it back to MyViewController.
After these steps you are able to connect buttons to the exit item again.
Xcode 6 Release Notes PDF, Page 10
Instead of using the Objective-C workaround, Xcode 6 Beta 4, which can now be installed, supports the connection of unwind segues in the Interface Builder. You can update now from the iOS Dev center. Control-click and drag from the UI item you want to trigger the segue to the exit icon, and select the function unwindToSegue after having put the following code in the destination view controller.
#IBAction func unwindToSegue (segue : UIStoryboardSegue) {}
I was able to finally get it to work; the xcode6 IB is really fragile right now (crashes a lot too). I had to restart the IDE before I could connect the nav bar button item to the exit item. I ended up re-creating my test project and following the above suggestion (Xcode 6 Release Notes PDF, Page 10) to get it to work. In addition, when adding the .h file, I made sure to select my project target, which was unchecked by default. I also created my controller swift stub via the Cocoa Touch Class template (vs empty swift file). I used a modal segue in my nav controller.
ListTableViewController.h
#import <UIKit/UIKit.h>
#interface ListTableViewController
- (IBAction)unwindToList: (UIStoryboardSegue *)segue;
#end
ListTableViewController.swift
import UIKit
#objc(ListTableViewController) class ListTableViewController: UITableViewController {
#IBAction func unwindToList(s:UIStoryboardSegue) {
println("hello world");
}
}
hope that helps
In Xcode 6 Beta 4 which is available for download, unwind segues and interface builder is supported. I have tested it by myself in a little project.
In Swift 2.3 I found the external name of the parameter must be "withUnwindSegue":
#IBAction func unwindToThisView(withUnwindSegue unwindSegue: UIStoryboardSegue) {
...
}
It appears that Xcode 6.1 has fixed this issue. You can now set up unwind segues in Swift with the following code:
#IBAction func unwindToList(segue: UIStoryboardSegue) {
// Nothing needed here, maybe a log statement
// print("\(segue)")
}
This method - which can remain empty - needs to have a method signature with the UIStoryboardSegue type and not AnyObject or Interface Builder will not see it.
For more detail check the TechNote 2298
I had the same problem, also with Xcode Beta 4 at the beginning.. till I found out, that I simply forgot to add the #IBOutlet for the Cancel and Save Buttons in the respective controller. After this, I could connect the buttons with the Exit-Icon :))
If it's always the same presenting view controller that you'd like to unwind to, you can always just do:
self.navigationController?.popViewControllerAnimated(true)
You may want to verify that the original controller destination that you're trying to unwind to is not embedded inside a Container object. Xcode 6 ain't having that.
The answers above rely on ObjC to fix the issue, I have found a pure Swift solution. While adding the segue handler in Swift allowed me to create the unwind segue in Interface Builder (Xcode 6.3), the handler was not being called.
#IBAction func unwindToParent(sender: UIStoryboardSegue) {
dismissViewControllerAnimated(true, completion: nil)
}
So after digging in, the canPerformUnwindSegueAction:fromViewController:withSender from the super class returns false. So I've overridden the implementation, and it works:
override func canPerformUnwindSegueAction(action: Selector, fromViewController: UIViewController, withSender sender: AnyObject) -> Bool {
return action == Selector("unwindToParent:")
}
Update
The code above is incorrect, as I resolved the issue without overriding canPerformUnwindSegueAction:fromViewController:withSender. The fundamental error was to make the distinction between the presenting viewcontroller and the presented viewcontroller.
When an unwind segue is initiated, it must first locate the nearest view controller in the navigation hierarchy which implements the unwind action specified when the unwind segue was created. This view controller becomes the destination of the unwind segue. If no suitable view controller is found, the unwind segue is aborted.
source: Technical Note TN2298
So, define the #IBAction on the presenting viewcontroller, not on the presented view controller. That way the segue will have meaningful values for the properties destinationViewController and sourceViewController as well, being respectively the presenting and presented viewcontroller.
Xcode --version 6.4
Swift 1.2
#IBAction func backButton(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil)
}
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 XCode project, which implements MultipeerConnectivity framework, I have a segue between two ViewControllers which is triggered programatically after MPCHandler successfully establishes connection with another peer. After segue is performed, the destination VC appears being completely blank (all white). However, if I try to access the destination VC with help of a button (with segue dragged directly from the button to the destination VC), it appears as it should.
Here is the line of code, which performs the segue:
performSegueWithIdentifier("seg_wait", sender: self)
So, yeah, I know how to perform segues and, yes, I made sure identifier is unique and is the same as in storyboard. I had tons of segues in many of my projects, and that's the first time I've faced a problem like this. Did anyone face a problem like this? Any ideas on how to solve it?
UI updates always have to be done on the main thread ("the law"). So try to wrap the call:
dispatch_async(dispatch_get_main_queue(), {
performSegueWithIdentifier("seg_wait", sender: self)
})
I know this was a problem in the Xcode betas and I read that this was fixed in the Xcode 6 GM, but I am having trouble with it now. I have create an unwind segue but it doesn't unwind properly. I have both views set to their respective custom View Controller, I have the unwind function in the view controller I want to unwind to, and this is the code I'm using:
#IBAction func unwindToObjectives(segue: UIStoryboardSegue) {
}
Can someone please help explain what I'm doing wrong? I know there is a work around, but I am trying to avoid using it. Also, I apologize for asking this menial question, I'm extremely new to Swift and iOS development.
I fixed the problem. In the end I just remade the custom TVC (with the segue), deleted the VC, and change the segue to a modal on and it work. I don't know how that helped, but it did.