-segueForUnwindingToViewController: fromViewController: identifier: not being called - ios

I have created a custom segue that presents a view controller inside a container that is very similar with Apple's own modal view controllers (I've implemented it as a UIViewController subclass).
I'm now trying to create a custom unwind segue but there's no way I can get the method -segueForUnwindingToViewController: fromViewController: identifier: to be called.
I've also implemented -viewControllerForUnwindSegueAction: fromViewController: withSender: on my container so I can point to the correct view controller (the one that presented this modal) but then the method that should be asked for my custom unwind segue doesn't get called anywhere.
Right now, the only way for me to dismiss this modal is to do it on the -returned: method.
Did anyone could successfully do this with a custom unwind segue?
EDIT:
A little bit more code and context
My unwind view controller is configured in the storyboard, not programatically.
I have these pieces of code related to the unwind segues in my controllers:
PresenterViewController.m
I'm using a custom method to dismiss my custom modals here (-dismissModalViewControllerWithCompletionBlock:).
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController
fromViewController:(UIViewController *)fromViewController
identifier:(NSString *)identifier {
return [[MyModalUnwindSegue alloc] initWithIdentifier:identifier
source:fromViewController
destination:toViewController];
}
-(IBAction)returned:(UIStoryboardSegue *)segue {
if ([segue.identifier isEqualToString:#"InfoUnwindSegue"]) {
[self dismissModalViewControllerWithCompletionBlock:^{}];
}
}
MyModalViewController.m
Here I only use -viewControllerForUnwindSegueAction: fromViewController: withSender: to point to the view controller that I should be unwind to.
- (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action
fromViewController:(UIViewController *)fromViewController
withSender:(id)sender {
return self.myPresentingViewController;
}
The behavior I was expecting was that MyModalViewController was called to point to the view controller that should handle the unwinding and then this view controller had his -segueForUnwindingToViewController: fromViewController: identifier: method called before -returned: gets called.
Right now -segueForUnwindingToViewController: fromViewController: identifier: never gets called.
I must also say that I already tried different configurations. Everywhere I put my method to return the unwind segue it never gets called. I've read that I can subclass a navigation controller and then it gets called but I don't know how it would fit in my solution.
EDIT 2: Additional info
I've checked that MyModalViewController has his -segueForUnwindingToViewController: fromViewController: identifier: method called when I want to dismiss a regular modal view controller presented by it. This may be because he's the top most UIViewController in the hierarchy.
After checking this I've subclassed UINavigationController and used this subclass instead to contain my PresenterViewController. I was quite surprised to notice that his -segueForUnwindingToViewController: fromViewController: identifier: method is called as well.
I believe that only view controllers that serve as containers have this method called. That's something that makes little sense for me as they are not the only ones presenting other view controllers, their children are also doing so.
It's not OK for me to create logic in this subclass to choose which segue class to use as this class has no knowledge of what their children did.
Apple forums are down for the moment so no way to get their support right now. If anyone has any more info on how this works please help! I guess the lack of documentation for this is a good indicator of how unstable this still is.

To add to the answer from #Jeremy, I got unwinding from a modal UIViewController to a UIViewController contained within a UINavigationController to work properly (I.e how I expected it to) using the following within my UINavigationController subclass.
// Pass to the top-most UIViewController on the stack.
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)
toViewController fromViewController:(UIViewController *)
fromViewController identifier:(NSString *)identifier {
UIViewController *controller = self.topViewController;
return [controller segueForUnwindingToViewController:toViewController
fromViewController:fromViewController
identifier:identifier];
}
.. and then implementing the segueForUnwindingToViewController as usual in the actual ViewController inside the UINavigationController.

This method should be declared on the parent controller. So if you're using a Navigation Controller with a custom segue, subclass UINavigationController and define this method on it. If you would rather define it on one of the UINavigationController's child views, you can override canPerformUnwindSegueAction:fromViewController:withSender on the UINavigationController to have it search the children for a handler.
If you're using an embedded view (container view), then define it on the parent view controller.
See the last 10 minutes of WWDC 2012 Session 407 - Adopting Storyboards in Your App to understand why this works!

If you're using a UINavigationController and your segue is calling pushViewController then in order to use a custom unwind segue you'll need to subclass UINavigationController and override - (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier.
Say I have a custom unwind segue called CloseDoorSegue. My UINavigationController subclass implementation might look something like:
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier {
UIStoryboardSegue* theSegue;
if ([identifier isEqualToString:#"CloseDoor"]) {
theSegue = [CloseBookSegue segueWithIdentifier:identifier source:fromViewController destination:toViewController performHandler:^(void){}];
} else {
theSegue = [super segueForUnwindingToViewController:toViewController fromViewController:fromViewController identifier:identifier];
}
return theSegue;
}
Set your UINavigationController subclass as the navigation controller class in the storyboard. You should be good to go provided you have setup the Exit event correctly with "CloseDoor" as the identifier. Also be sure to call 'popViewControllerAnimated' in your unwind segue instead of dismiss to keep in line with UINavigationControllers push/pop mechanism.

iOS development Library
There is a discussion on iOS development Library along with this method.
- segueForUnwindingToViewController:fromViewController:identifier:
Make sure your MyModalViewController is the container role rather than a subcontroller of a container. If there is something like [anotherVC addChildViewController:myModalViewController];,you should put the segueForUnwindingToViewController method in some kind of "AnotherVC.m" file.
Discussion
If you implement a custom container view controller that
also uses segue unwinding, you must override this method. Your method
implementation should instantiate and return a custom segue object
that performs whatever animation and other steps that are necessary to
unwind the view controllers.

Related

Custom Unwind Segue for iOS 8 and iOS 9

My question is, how do I get the following custom unwind segue to work on a device with a version prior to iOS 9 as well as on a device running iOS 9?
I have a Custom Segue showing a view controller, and then have a corresponding Custom Unwind Segue. This code has worked fine in iOS 8, and is implemented by creating subclasses of UIStoryboardSegue and implementing the perform method. Then I override the following method in my custom Navigation Controller:
- (UIStoryboardSegue *) segueForUnwindingToViewController: (UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier
{
UIStoryboardSegue *segue;
if([fromViewController isKindOfClass:[MyViewController class]]){
segue = [[CustomSegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController]; //Custom Unwind Segue
}
else{
UIStoryboardSegue *unwindSegue = [super segueForUnwindingToViewController:toViewController fromViewController:fromViewController identifier:identifier]; //Normal Unwind Segue
segue = unwindSegue;
}
return segue;
}
In iOS 9, segueForUnwindingToViewController is deprecated. It still works for the MyViewController CustomSegue; however, the default unwind segue no longer works for any other unwind segue. Although calling the method on super returns an unwind segue, the segue never occurs, the view controller is never popped, and the user can never go back to the previous screen. So just to be clear, if I use a regular show segue, the corresponding unwind segue calls the deprecated method, which calls the method on super, and does not work.
I watched the WWDC talk on storyboards, and I was able to fix this issue in iOS 9 by a) no longer overriding this method in my custom Navigation Controller, and b) going into the storyboard, clicking on the custom segue, and entering in CustomSegue as the Segue Class. Unfortunately, since I am targeting iOS 7, I get the warning "Only Custom segues support class names prior to iOS 9", and the custom unwind segue now does not work for iOS 7 or iOS 8!
After a lot of trial and error, I found a workaround. I noticed that when you override segueForUnwindingToViewController, unwindForSegue:towardsViewController is no longer called, which is the problem. FYI, Apple's note in UIViewController for segueForUnwindingToViewController says:
Deprecated. Returns a segue that will unwind from the source to destination view controller via the unwindForSegue:towardViewController: method. When performing an unwind segue defined in a storyboard, if any view controller along the unwind path has overridden this method and returns non-nil, the runtime will use that segue object instead of constructing an instance of the class specified in Interface Builder.
The portion of the statement in bold does not seem to be implemented, i.e. if you override this method but return nil, unwindForSegue:towardViewController is still not called and the segue does not occur.
In order to get around this problem, I was able to edit the segueForUnwindingToViewController in my custom Navigation Controller:
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier
{
UIStoryboardSegue *segue;
if([fromViewController isKindOfClass:[MyViewController class]]){
segue = [[CustomSegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController]; //Custom Unwind Segue
}
else{
if([[UIDevice currentDevice].systemVersion floatValue] < 9.0){
return [super segueForUnwindingToViewController:toViewController fromViewController:fromViewController identifier:identifier]; //Normal Unwind Segue
}
else{
[super unwindForSegue:segue towardsViewController:toViewController];
return nil;
}
}
return segue;
}
UPDATE: Calling [super segueForUnwindingToViewController:toViewController fromViewController:fromViewController identifier:identifier]; seems to still work for modal unwind segues. The issue I described seems to happen for show segues. Consequently, if your device runs on a version < 9.0 or if the segue is modal, you should still call the old method. If you call [super unwindForSegue:segue towardsViewController:toViewController]; when the segue is modal, the segue will not work/occur.
I slightly modified your code.
I don't have to consider whether push or modal.
It seems to work fine.
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier
{
UIStoryboardSegue *segue;
if ([fromViewController isKindOfClass:[MyViewController class]]) {
segue = [[CustomSegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController]; //Custom Unwind Segue
}
else {
if ([super respondsToSelector:#selector(unwindForSegue:towardsViewController:)]) {
[super unwindForSegue:segue towardsViewController:toViewController];
}
segue = [super segueForUnwindingToViewController:toViewController fromViewController:fromViewController identifier:identifier];
}
return segue;
}

Call custom transition animator using a programmatically created segue IOS

the project I am working on needs to have a custom transition between two view controllers. I have setup and implemented UIViewControllerTransitioningDelegate by overriding the method like:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC
{
//Creation of animation
id<UIViewControllerAnimatedTransitioning> animationController;
MyAnimator *animator = [[MyAnimator alloc] init];
animator.appearing = YES;
animationController = animator;
return animator
}
And I have setup MyAnimator subclass to correctly implement UIViewControllerAnimatedTransitioning by overriding the method:
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
{
//custom transition animation
}
The segue which I using to trigger this animation transition is created and called programmatically, like:
UIStoryboardSegue *segue = [[UIStoryboardSegue alloc] initWithIdentifier:#"showCardDetail" source:self destination:vc];
[self prepareForSegue:segue sender:self];
[segue perform];
Reason of creating segue programmatically: I have from(transition from) and to(transition to) view controllers in separate storyboards.
Problem / Question:
I have seen many examples, all handle the custom transition using a storyboard segue like:
[self performSegueWithIdentifier:#"storyboardSegue-id" sender:self]
How should i define in the method -perform for segue created programmatically above so that the custom transition takes place.
You don't need to create a custom segue to do what you're trying to do. In fact, since you have your 2 controllers in separate storyboards, you shouldn't use a segue at all. Just instantiate your destination view controller, and use pushViewController:animated: to initiate the transition. Your first view controller should be the delegate of the navigation controller, so the delegate method you show at the top of your question gets called.
In navigationControllerAnimationControllerForOperation:fromViewController:toViewController: you can adjust source and destination viewControllers and based on this types you will see desired animation. You do not need to use prepareForSegue: here.

How to unwind through multiple views without displaying intermediate views

Assume we have three view controllers: 1, 2, and 3. Using the storyboard, it's pretty simple to unwind from view controller 3 to view controller 1 using an unwind segue. However, when unwinding, view controller 2 is briefly visible before view controller 1 is displayed. Is there any way to get from 3 to 1 without displaying 2 again?
View Controller 1:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"one did appear");
}
- (IBAction)goToTwo:(id)sender {
NSLog(#"#### segue to two");
[self performSegueWithIdentifier:#"TwoSegue" sender:self];
}
- (IBAction)unwindToOne:(UIStoryboardSegue *)sender {
}
View Controller 2:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"two did appear");
}
- (IBAction)goToThree:(id)sender {
NSLog(#"#### segue to three");
[self performSegueWithIdentifier:#"ThreeSegue" sender:self];
}
View Controller 3:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"three did appear");
}
- (IBAction)unwindToOne:(id)sender {
NSLog(#"#### unwind to one");
[self performSegueWithIdentifier:#"OneSegue" sender:self];
}
This produces the following log messages:
one did appear
segue to two
two did appear
segue to three
three did appear
unwind to one
two did appear
one did appear
I've tried using custom segues and disabling animation. Although removing animation makes view controller 2 appear for an even shorter period of time, it still appears. Is there any way to program this behavior?
Screenshot of storyboard:
This seems to be due to the way that unwind segues search for the nearest view controller which implements the unwind action you specified in the storyboard. From the documentation:
How an Unwind Segue Selects its Destination
When an unwind segue is triggered, it must locate the nearest view controller that implements the unwind action specified when the unwind segue was defined. This view controller becomes the destination of the unwind segue. If no suitable view controller is found, the unwind segue is aborted. The search order is as follows:
A viewControllerForUnwindSegueAction:fromViewController:withSender: message is sent to the parent of the source view controller.
A viewControllerForUnwindSegueAction:fromViewController:withSender: message is sent to the next parent view controller [...]
You can override canPerformUnwindSegueAction:fromViewController:withSender: if you have specific requirements for whether your view controller should handle an unwind action.
The view controllers in your example don't have a parent, so it seems that the fallback (which I can't see documentation for) is to instantiate each presentingViewController and call canPerformUnwindSegueAction on them in turn. Returning NO from this method in ViewControllerTwo doesn't prevent its instantiation and display, so that doesn't solve the issue.
I've tried your code embedded within a navigation controller, and it works fine. This is because in that case, UINavigationController is the parent of each of your view controllers, and it handles all the selection of a destination view controller. More documentation:
Container View Controllers
Container view controllers have two responsibilities in the unwind process, both discussed below. If you are using the container view controllers provided by the SDK, such as UINavigationController, these are handled automatically.
If you were to create a simple container view controller to act as the parent for your three view controllers, you could use its viewControllerForUnwindSegueAction method to check each of its child controllers for the existence of the unwind action, before calling canPerformUnwindSegueAction on that controller, and finally returning the first one of those which returns YES.
Selecting a Child View Controller to Handle An Unwind Action
As mentioned in How an Unwind Segue Selects its Destination, the source view controller of an unwind segue defers to its parent to locate a view controller that wants to handle the unwind action. Your container view controller should override the method shown in Listing 2 to search its child view controllers for a view controller that wants to handle the unwind action. If none of a container's child view controllers want to handle the unwind action, it should invoke the super's implementation and return the result.
A container view controller should search its children in a way that makes sense for that container. For example, UINavigationController searches backwards through its viewControllers array, starting from the view at the top of the navigation stack.
Listing 2 Override this method to return a view controller that wants to handle the unwind action.
- (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
Container view controller design has a whole article dedicated to it by Apple, which I won't duplicate here (more than enough of Apple's writing in this answer already!) but it looks like it will take some thought to get it right, as it depends on the exact role you want these to play in your application.
A quick workaround, to get your desired behaviour using unwind segues, could be to embed the view controllers in a UINavigationController, and then hide the navigation bar using
[self.navigationController setNavigationBarHidden:YES];
Josh's answer led me to a solution. Here's how to accomplish this:
Create a root UINavigationController, and assign it to a class that extends UINavigationController and overrides the segueForUnwindingToViewController:fromViewController:identifier method. This could be filtered by the identifier if desired.
CustomNavigationController:
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier {
return [[CustomUnwindSegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController];
}
Create a custom push segue, that behaves like a modal segue, but utilizes our navigation controller. Use this for all "push" segues.
CustomPushSegue:
-(void) perform{
[[self.sourceViewController navigationController] pushViewController:self.destinationViewController animated:NO];
}
Create a custom unwind segue, that uses the navigation controller to pop to the destination. This is called by our navigation controller in the segueForUnwindingToViewController:fromViewController:identifier method.
CustomUnwindSegue:
- (void)perform {
[[self.destinationViewController navigationController] popToViewController:self.destinationViewController animated:NO];
}
By utilizing a combination of these patterns, the second view controller never appears during the unwind process.
New log output:
one did appear
#### segue to two
two did appear
#### segue to three
three did appear
#### unwind to one
one did appear
I hope this helps someone else with the same issue.
Looks like custom segues are being used, so it's possible that's interfering somehow, although I've never seen it happn. I suggest you check out Apple's example project. It also has custom segues in it so it should serve as a good starting point for you.
Apple's Unwind Segue Example
I surprised you're seeing the behavior you're seeing, but one way to change it would be to use an explicit dismiss rather than unwind segues (this assumes the forward segues are modal).
Everything will look right if VC1 does this:
[self dismissViewControllerAnimated:YES completion:^{}];
Or if some other vc does this:
[vc1 dismissViewControllerAnimated:YES completion:^{}];
The only hitch is that you'll need a handle to vc1 if you want to dismiss from some other vc. You could use a delegate pattern to let vc1 know it should do the dismiss, but a simpler solution is to have vc2 or 3 post a notification when the unwind should happen.
VCs 2 or 3 can do this:
// whenever we want to dismiss
[[NSNotificationCenter defaultCenter] postNotificationName:#"TimeToDismiss" object:self];
And VC1 can do this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(doDismiss:)
name:#"TimeToDismiss"
object:nil];
- (void)doDismiss:(NSNotification *)notification {
[self dismissViewControllerAnimated:YES completion:^{}];
}

iOS 8 kills Unwind Segues [duplicate]

I have an app, that works fine under iOS 7, but when built for iOS 8 the unwind segues are not working.
I created a new project and added a modal (navigationcontroller with tableviewcontroller)and tried to use an unwind modal. Unfortunately it doesn't work either. The methods that are being unwind to, are in the desination view controller. The unwind segue is created through the storyboard (a Navigationbar button in the tableviewcontroller) When I tap the button, nothing happens. There is no log output and the modal does not disappear. It also only seems to affect modal segues. push/popover are unwound normally.
Has anyone had a similar problem and has an Idea how I could solve it?
Apple has FIXED this bug in iOS 8.1
Temporary solutions for iOS 8.0
The unwind segue will not work only in next situation:
View structure: UITabBarController -> UINagivationController -> UIViewController1 -> UIViewController2
Normally (in iOS 7, 8.1), When unwind from UIViewController2 to UIViewController1, it will call viewControllerForUnwindSegueAction in UIViewController1.
However in iOS 8.0 and 8.0.x, it will call viewControllerForUnwindSegueAction in UITabBarController instead of UIViewController1, that is why unwind segue no longer working.
Solution: override viewControllerForUnwindSegueAction in UITabBarController by create a custom UITabBarController and use the custom one.
For Swift
CustomTabBarController.swift
import UIKit
class CustomTabBarController: UITabBarController {
override func viewControllerForUnwindSegueAction(action: Selector, fromViewController: UIViewController, withSender sender: AnyObject?) -> UIViewController? {
var resultVC = self.selectedViewController?.viewControllerForUnwindSegueAction(action, fromViewController: fromViewController, withSender: sender)
return resultVC
}
}
For old school Objective-C
CustomTabBarController.h
#import <UIKit/UIKit.h>
#interface CustomTabBarController : UITabBarController
#end
CustomTabBarController.m
#import "CustomTabBarController.h"
#interface CustomTabBarController ()
#end
#implementation CustomTabBarController
-(UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
{
return [self.selectedViewController viewControllerForUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
}
#end
==============================================================================
DO NOT USE ANY SOLUTIONS BELOW THIS POINT (they are out of date and just for reference)
Latest update on Sep 23
My new solution is pushing to a view that embedded in a navigation controller, and config that navigation controller to hide bottom bar on push(a tick box in IB). Then you will have a view looks like a modal view, the only different is the animate of pushing and popping. You can custom if you want
Updated: The solution below actually present the modal view under the tab bar, which will cause further view layout problems.
Change the segue type to Present As Popover will work only on iOS8 for iPhones, on iOS7 your app will crash.
Same here, to fix this, I set segue's presentation to current context(my app is for iphone only).
Default and full screen will not work.
[UPDATE: Bug fixed on iOS 8.1 beta but you'll need it for 8.0 and 8.0.2 support]
The only way I could make my unwind segue work was by mixing Aditya's and viirus' answers.
My setup going in:
[View Controller 1] > custom modal segue > [Navigation Controller] > root > [View Controller 2]
Unwind:
[View Controller 2] > custom unwind segue > [View Controller 1]
Fix:
Subclass the [Navigation Controller], add a property called sourceViewController and pass "self" to that property when prepare for segue is called when going from [View Controller 1] to [Navigation Controller]
In the [Navigation Controller] subclass .m override/add this two methods:
- (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
{
if ([self.sourceViewController canPerformUnwindSegueAction:action fromViewController:fromViewController withSender:sender]) {
return self.sourceViewController;
}
return [super viewControllerForUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
}
Then I override this in that [Navigation Controller] subclass only because I have a custom unwind segue:
- (UIStoryboardSegue *)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier {
return [fromViewController segueForUnwindingToViewController:toViewController
fromViewController:fromViewController
identifier:identifier];
}
This is a problem with iOS 8.0, 8.0.1, and 8.0.2. It was resolved in 8.1; unwind segues are calling the appropriate method now.
Note that on iOS 8, modally presented view controllers may not be automatically dismissed when performing an unwind segue, unlike iOS 7. To ensure it's always dismissed, you may detect if it's being dismissed and if not then manually dismiss it. These inconsistencies are resolved in iOS 9.0.
With iOS 8.4 running on iPhone, all of the modally presented segues with all presentation styles do dismiss upon unwind, except Over Full Screen and Over Current Context. That's also the case for iPad, with the addition of Form Sheet and Page Sheet also not auto-dismissing. With iOS 9, all presentation styles auto dismiss on both iPhone and iPad.
Yep it kinda happen to me too, I think for your case you have to subclass the UINavigationController and override the following:
- (UIViewController *)viewControllerForUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender
{
for(UIViewController *vc in self.viewControllers){
// Always use -canPerformUnwindSegueAction:fromViewController:withSender:
// to determine if a view controller wants to handle an unwind action.
if ([vc canPerformUnwindSegueAction:action fromViewController:fromViewController withSender:sender])
return vc;
}
return [super viewControllerForUnwindSegueAction:action fromViewController:fromViewController withSender:sender];
}
Same problem here. Unwind method is not called. Only happens when
using modal segue
Presentation is anything but "current context"
NavigationController is not extended (using default from storyboard)
Also happens in IOS8 GM Seed, therefore I think we need to find a workaround.
Sounds like a bug to me...
Extending UINavigationController and implementing viewControllerForUnwindSegueAction didn't help, as it is not fired. The only thing which gets fired is canPerformUnwindSegueAction() within the extended UINavigationController. Strange.
Woah there! I'm still getting user reports of getting stuck on a modal view in iOS 8.1.1 (on an iPad 3).
I'm jettisoning all this unwind from a modal view stuff. Just a good old-fashioned...
[self dismissViewControllerAnimated:NO completion:nil];
...works fine on all those various iOS 8.x.x versions.
It seems that both iOS 7.1 and iOS 8.1/8.2 create unwind segue from navigation controller however unwind segue is registered on a child controller inside of navigation controller.
So manually creating an unwind segue from the controller where it's registered in storyboard solves the problem.
#implementation RootNavigationController
- (UIStoryboardSegue*)segueForUnwindingToViewController:(UIViewController *)toViewController fromViewController:(UIViewController *)fromViewController identifier:(NSString *)identifier {
return [toViewController segueForUnwindingToViewController:toViewController fromViewController:fromViewController identifier:identifier];
}
#end
I encountered the same problem when unwinding to a source view controller from a destination view controller. The destination was presented through a "show" segue from the source.
I was using iPhone simulator that shows iPhone 6, iOS8.3.
XCode 6.3.2
The solution of subclassing NavigationViewController worked for me. Here is the swift code which is essentially swift translation of Raul's answer. I am puzzled that if Apple has fixed it in iOS8.1 per Raul, how am I getting hit by it in 8.3.
var sourceViewController: UIViewController?
override func viewControllerForUnwindSegueAction(action: Selector, fromViewController: UIViewController, withSender sender: AnyObject?) -> UIViewController? {
if(self.sourceViewController! .canPerformUnwindSegueAction(action, fromViewController: fromViewController, withSender: sender!)){
return self.sourceViewController
}
return super.viewControllerForUnwindSegueAction(action, fromViewController: fromViewController, withSender: sender)
}
I just ran into this problem, and after some digging discovered that with modal segues (at least ones with the default and fullscreen presentation modes), you can't rely on the normal unwind mechanism, but rather you have to call the presented UIViewController's dismissViewControllerAnimated method.
Steps to be followed:
Link the unwind segue to the button in Storyboard.
Create IBAction for the button and add the below code in it:
[self dismissViewControllerAnimated:NO completion:nil];
This should work for all versions.

How to select the right parent view controller

I have a child view controller called by two view controllers placed in different places in the storyboard. In this child there is a button to close the actual view, i want to assign an IBAction or a Segue to connect this view with is real parent view controller.
Maybe i'm wrong but it's possible to do this with an Unwind Segue?? This is the first time i have to use those, somebody could help me please?
Thanks a lot! Peace
What's the relationship between the parent and the child? Is it pushed on the navigation controller or presented (modally)? Then you can use in the case of UINavigationController
- (UIViewController *)popViewControllerAnimated:(BOOL)animated; // Returns the popped controller.
or in case of presented (modally) viewcontroller
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^)(void))completion NS_AVAILABLE_IOS(5_0);
You can also use unwinding segues of course, check out this tutorial.
No matter the viewController you're using, you can access its parent by calling :
// < iOS 5
[myViewController parentViewController]
// >= iOS 5
[myViewController presentingViewController]
After getting it you'll just have to check which one it :
if ([[myViewController presentingViewController] isKindOfClass:[myParentClassA class]])
{
// do anything
}
It is possible to create unwind methods with the same name in both parent view controllers:
- (IBAction)unwindToThisViewController:(UIStoryboardSegue *)segue {
}
The unwind mechanism automatically will walk through the responder chain and find the correct parent view controller

Resources