Ios – Dismiss Popover using Unwind Segue in Xcode Storyboard

iosobjective cuipopovercontrolleruistoryboardseguexcode4.5

I am using Xcode 4.5 and the new iOS 6 feature to unwind segues. I am presenting a navigation view controller inside a popover which is presented programmatically from a bar button item:

- (IBAction)configChartTapped:(id)sender
{
    if (self.popover.isPopoverVisible) {

        [self.popover dismissPopoverAnimated:YES];

    } else {
        UINavigationController *chartConfigNavigationController = [self.storyboard instantiateViewControllerWithIdentifier:@"GrowthChartNavigationController"];

        ConfigChartTypeViewController *configChartTypeViewController = (ConfigChartTypeViewController*) chartConfigNavigationController.topViewController;

        self.popover = [[UIPopoverController alloc]initWithContentViewController:chartConfigNavigationController];
        self.popover.popoverContentSize = CGSizeMake(320, 500);
        self.popover.delegate = self;

        [self.popover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
    }
}

Next to this method I have defined a target to unwind the segue (i.e. dismissing the popover)…

- (IBAction)cancelConfig:(UIStoryboardSegue *)segue
{
    //
}

… and connected it to a cancel button in the navigation view controllers's navigation bar.

Connecting the cancel bar button to the cancelConfig button worked fine in Xcode.

However, when running the code, nothing happens when clicking on the Cancel button despite Xcode 4.5 should be supporting dismissing popovers when unwinding segues (according to the release docs).

What did I miss?

Thank you!

Best Answer

Unwind segues use runtime searching by first asking the parent view controller to walk up the chain of view controllers presented via segue until it finds the correct unwind method. But there is no chain here since the popover was created programmatically rather than with a popover segue.

No callbacks are occurring since there is no segue link back to the parent view controller. Unwind segues are an abstracted form of delegation, so this would be similar to forgetting to set the delegate and not receiving any callbacks.

The solution is to create the popover with a segue in Interface Builder rather than create it programmatically with the configChartTapped: method.

Steps:

First, control-drag from the bar button item in the presenting view controller to the presented view controller and select the popover segue:

enter image description here

In the presenting view controller, implement prepareForSegue: to grab a reference to the popover controller:

- (void)prepareForSegue:(UIStoryboardPopoverSegue *)segue
                 sender:(id)sender {
    self.popover = segue.popoverController;
}

Then implement shouldPerformSegueWithIdentifier: to restore the show/hide behavior similar to configChartTapped::

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender {
    if (self.popover.isPopoverVisible) {
        [self.popover dismissPopoverAnimated:YES];
        return NO;
    } else {
        return YES;
    }
}

Finally, in Interface Builder, set the correct popover content size for the presented view controller:

enter image description here

This will allow you to unwind to cancelConfig: when tapping the cancel button from the popover, and also show/hide the popover when tapping the button that presents it.

Related Topic