How to do something before unwind segue action?
You can do it the way you describe, or by using a prepareForSegue
override function in the viewController you are unwinding from:
@IBAction func actionForUnwindButton(sender: AnyObject) {
println("actionForUnwindButton");
}
or...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
println("prepareForSegue");
}
The first example is as you describe. The button is wired up to the unwind segue and to the button action in Interface Builder. The button action will be triggered before the segue action. Perhaps you didn't connect the action to the button in interface builder?
The second example gives you have access to the segue's sourceViewController
and destinationViewController
in case that is also useful (you also get these in the unwind segue's function in the destination view controller).
If you want to delay the unwind segue until the button's local action is complete, you can invoke the segue directly from the button action (instead of hooking it up in the storyboard) using self.performSegueWithIdentifier
(or follow wrUS61's suggestion)
EDIT
you seem to have some doubts whether you can work this by wiring up your button both to an unwind segue and to a button action. I have set up a little test project like this:
class BlueViewController: UIViewController {
@IBAction func actionForUnwindButton(sender: AnyObject) {
println("actionForUnwindButton");
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
println("prepareForSegue");
}
}
class RedViewController: UIViewController {
@IBAction func unwindToRed(sender: UIStoryboardSegue) {
println("unwindToRed");
}
}
BlueViewController has a button that is connected in the storyboard to BOTH the unwindToRed
unwind segue AND the actionForUnwindButton
button. It also overrides prepareForSegue
so we can log the order of play.
Output:
actionForUnwindButton
prepareForSegue
unwindToRed
Storyboard:
EDIT 2
your demo project shows this not working. The difference is that you are using a barButtonItem to trigger the action, whereas I am using a regular button. A barButtonItem fails, whereas a regular button succeeds. I suspect that this is due to differences in the order of message passing (what follows is conjecture, but fits with the observed behaviour):
(A) UIButton in View Controller
ViewController's button receives touchupInside
- (1) sends action to it's method
- (2) sends segue unwind action to storyboard segue
all messages received, and methods executed in this order:
actionForUnwindButton
prepareForSegue
unwindToRed
(B) UIBarButtonItem in Navigation Controller Toolbar
Tool bar buttonItem receives touchupInside
- (1) sends segue unwind action to storyboard segue
- (2) (possibly, then) sends action to viewController's method
Order of execution is
prepareForSegue
unwindToRed
actionForUnwindButton
prepareForSegue
and unwind
messages received. However actionForUnwindButton
message is sent to nil as viewController is destroyed during the segue. So it doesn't get executed, and the log prints
prepareForSegue
unwindToRed
In the case of (B), the viewController is destroyed before the method reaches it, so does not get triggered
So it seems your options are...
(a) use a UIButton with action and unwind segue
(b) trigger your actions using prepareForSegue
, which will be triggered while the viewController is still alive, and before the segue takes place.
(c) don't use an unwind segue, just use a button action. In the action method you can 'unwind' by calling popToViewController
on your navigation controller.
By the way, if you implement a toolBar on the viewController (not using the navigation controller's toolbar) the result is the same: segue gets triggered first, so button action fails.
Do something BEFORE unwind segue (swift)
This expression: dispatch_async(dispatch_get_global_queue(priority, 0)
will perform everything in the background (until you do something again explicitly on the main queue).
Simply eliminate all dispatch_async
calls to do all the work on the main thread. If it takes too long, notify the user so he knows there is a short wait until the unwind segue fires.
How to perform action before triggering exit segue?
Remove the exit segue from the button and instead simply link the button to a new IBAction and insert
self.dismissViewControllerAnimated(true, completion: nil)
So, your new code would be:
@IBAction func saveFriendRequest(sender: AnyObject) {
//Do your stuff to save the friend request
self.dismissViewControllerAnimated(true, completion: nil)
}
how to perform Condition check, before segue unwind
To achieve this, connect Controller
of VC3
to its own exit and select the unwind action.
Give this exit-segue a segue.identifier
"YOUR EXIT TEXT"
Still in VC3
, create an IBAction
for the "Accept" button.
@IBAction func accept(sender: AnyObject) {
if //Condition X is true
{performSegueWithIdentifier("YOUR EXIT TEXT", sender: self)}
else {
//Do this
}
Show UIAlert before unwinding segue
Instead of perform the segue directly you need to show your UIAlertViewController
first and according to the user response execute your segue
or not
@IBAction func showAlertViewController(){
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let replyAction = UIAlertAction(title: "Delete Draft", style: .destructive, handler: nil)
let replyAllAction = UIAlertAction(title: "Save Draft", style: .default) { (action) in
//Do whatever you need here
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
self.performSegue(withIdentifier: "cancelDraft", sender: action) //executing the segue on cancel
}
alertController.addAction(replyAllAction)
alertController.addAction(replyAction)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
After this you only need to change the unwind segue action to execute this method, and your segue will be executed if you press cancel in the UIAlertViewController
via self.performSegue(withIdentifier: #<SegueIdentifier>, sender: #<sender>)
Use existing unwind segue from another action
Create a second unwind segue by control-dragging from your Delete button to the Exit icon. You can even use the existing @IBAction
in your destination viewController. Give this segue an identifier (select the segue in the Document Outline view and set the identifier in the Attributes Inspector) such as "deleteSegue"
and then in prepare(for:sender)
check for the identifier and delete the info from Firebase.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "deleteSegue" {
// delete data from Firebase
}
}
Follow up question from the comments:
I want to perform an action BEFORE unwinding the segue - I want a
popup to ask the user if he really wants to delete the item. only
after that I want the item deleted and segue unwinded.
Instead of wiring the unwind segue from the Delete button, wire it from the viewController icon at the top of the VC to the Exit icon. Still give it the identifier and then call performSegue(withIdentifier: "deleteSegue", sender: self)
when you want to perform the segue.
How to perform action before triggering exit segue?
Remove the exit segue from the button and instead simply link the button to a new IBAction and insert
self.dismissViewControllerAnimated(true, completion: nil)
So, your new code would be:
@IBAction func saveFriendRequest(sender: AnyObject) {
//Do your stuff to save the friend request
self.dismissViewControllerAnimated(true, completion: nil)
}
What are Unwind segues for and how do you use them?
In a Nutshell
An unwind segue (sometimes called exit segue) can be used to navigate back through push, modal or popover segues (as if you popped the navigation item from the navigation bar, closed the popover or dismissed the modally presented view controller). On top of that you can actually unwind through not only one but a series of push/modal/popover segues, e.g. "go back" multiple steps in your navigation hierarchy with a single unwind action.
When you perform an unwind segue, you need to specify an action, which is an action method of the view controller you want to unwind to.
Objective-C:
- (IBAction)unwindToThisViewController:(UIStoryboardSegue *)unwindSegue
{
}
Swift:
@IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
}
The name of this action method is used when you create the unwind segue in the storyboard. Furthermore, this method is called just before the unwind segue is performed. You can get the source view controller from the passed UIStoryboardSegue
parameter to interact with the view controller that initiated the segue (e.g. to get the property values of a modal view controller). In this respect, the method has a similar function as the prepareForSegue:
method of UIViewController
.
iOS 8 update: Unwind segues also work with iOS 8's adaptive segues, such as Show and Show Detail.
An Example
Let us have a storyboard with a navigation controller and three child view controllers:
From Green View Controller you can unwind (navigate back) to Red View Controller. From Blue you can unwind to Green or to Red via Green. To enable unwinding you must add the special action methods to Red and Green, e.g. here is the action method in Red:
Objective-C:
@implementation RedViewController
- (IBAction)unwindToRed:(UIStoryboardSegue *)unwindSegue
{
}
@end
Swift:
@IBAction func unwindToRed(segue: UIStoryboardSegue) {
}
After the action method has been added, you can define the unwind segue in the storyboard by control-dragging to the Exit icon. Here we want to unwind to Red from Green when the button is pressed:
You must select the action which is defined in the view controller you want to unwind to:
You can also unwind to Red from Blue (which is "two steps away" in the navigation stack). The key is selecting the correct unwind action.
Before the the unwind segue is performed, the action method is called. In the example I defined an unwind segue to Red from both Green and Blue. We can access the source of the unwind in the action method via the UIStoryboardSegue parameter:
Objective-C:
- (IBAction)unwindToRed:(UIStoryboardSegue *)unwindSegue
{
UIViewController* sourceViewController = unwindSegue.sourceViewController;
if ([sourceViewController isKindOfClass:[BlueViewController class]])
{
NSLog(@"Coming from BLUE!");
}
else if ([sourceViewController isKindOfClass:[GreenViewController class]])
{
NSLog(@"Coming from GREEN!");
}
}
Swift:
@IBAction func unwindToRed(unwindSegue: UIStoryboardSegue) {
if let blueViewController = unwindSegue.sourceViewController as? BlueViewController {
println("Coming from BLUE")
}
else if let redViewController = unwindSegue.sourceViewController as? RedViewController {
println("Coming from RED")
}
}
Unwinding also works through a combination of push/modal segues. E.g. if I added another Yellow view controller with a modal segue, we could unwind from Yellow all the way back to Red in a single step:
Unwinding from Code
When you define an unwind segue by control-dragging something to the Exit symbol of a view controller, a new segue appears in the Document Outline:
Selecting the segue and going to the Attributes Inspector reveals the "Identifier" property. Use this to give a unique identifier to your segue:
After this, the unwind segue can be performed from code just like any other segue:
Objective-C:
[self performSegueWithIdentifier:@"UnwindToRedSegueID" sender:self];
Swift:
performSegueWithIdentifier("UnwindToRedSegueID", sender: self)
Related Topics
Swiftui Buttonstyle - How to Check If Button Is Disabled or Enabled
Xcode 8 Swift 3 Uitableview Space Between Cells
Swrevealviewcontroller Close Rear View When Tapping Front View
How to Access iOS Private APIs in Swift
Override Uiappearance Property for Mfmailcomposeviewcontroller
iOS 8+ Framework with Nested Embedded Framework
Embedding a Framework Within a Framework (iOS 8+)
Uicontroleventeditingchanged Doesn't Get Fired When Using Settext of Uitextfield
Completely Disable Firebase/Analytics to Stop Console Spam on App Startup
Firinstanceid/Warning Stop!! Will Reset Deviceid from Memory [Xcode:Console Log]
Xctest Build Errors for Test Target Xcode 5:
Background User Location When App Is Terminated/Suspended
Share Image with Hashtag via Uiactivityviewcontroller (Twitter, Facebook, Instagram)
Domain=Nsurlerrordomain Code 1202
Swrevealviewcontroller - Manually Switch to Another View