How to dismiss a Popover from the current UIViewController

Imagine you’re presenting a view controller in your storyboard via a Popover Segue: Simply drag from a button in your Main View Controller to your Other View Controller, and under segue select “Popover”. Works like a charm: the popover is presented, and if someone clicks outside the popover it is dismissed. Marvellous!

Surely we should be able to add a button inside our popover, and create an IBAction in which we call something like “dismissPopover:animated”. But of course there isn’t – at least not if you’re presenting a UIViewController.

Things would be easier if we had created our popover in code, where we could create a UIPopoverController (which has a method that dismisses it) – but if you’ve ever tried, that’s just not possible when using Storyboards: because with Storyboards, all we can create is a UIViewController, and it just doesn’t have a popover dismissal method.

So how do we do this instead?

First we’ll create a reference to the UIPopoverController the segue will initiate for us, then we’ll call the dismissPopover:animated method on it from the class that has presented it via an observer.

Let’s do this thing!

In our Main View Controller (i.e. the one that’s bringing up the popover), we’ll add a weak property to hold that reference. We’ll also need two methods, the prepareForSegue:sender, and one to dismiss the popover. We also need to setup an observer:

#import "ViewController.h"

@interface ViewController ()

@property (weak) UIPopoverController *settingsPopover;

@end

@implementation ViewController


- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // add popover dismissal observer
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(dismissPopover) name:@"dismissSettingsPopover" object:nil];
}

#pragma mark - The Popover Challenge

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    
    if ([segue.identifier isEqualToString:@"settingsPopover"]) {
        self.settingsPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
    }
}

- (void)dismissPopover {
    [self.settingsPopover dismissPopoverAnimated:YES];
}

@end

Nothing unusual here, except perhaps for how we grab the reference to the UIPopoverController. We’re typecasting the segue as a popover segue so we can extract the actual popover controller from it.

Note that I’ve named the popover segue in the storyboard (as settingsPopover). The dismissPopover method is something that we’ll call via an observer, setup in viewDidLoad.

Next up: the actual UIViewController that we’ve created in the storyboard. This will serve as the content for the popover controller which will be generated automatically for us via the segue that’s defined as “popover segue” in the Storyboard. All we do here is to hook up that “dismiss button” to an IBAction which in turn will send a message:

- (IBAction)dismissView:(id)sender {
    
    // send a message, which when picked up will dismiss this view
    [[NSNotificationCenter defaultCenter]postNotificationName:@"dismissSettingsPopover" object:self];
}

This notification is picked up by our Main View Controller which acts accordingly and can dismiss our popover because it holds a reference to it.

Another mystery solved ;-)





Jay is the CEO and founder of WP Hosting, a boutique style managed WordPress hosting and support service. He has been working with Plesk since version 9 and is a qualified Parallels Automation Professional. In his spare time he likes to develop iOS apps and WordPress plugins, or draw on tablet devices. He blogs about his coding journey at http://wpguru.co.uk and http://pinkstone.co.uk.