Code and hint
A little more background. I'm not entirely sure popover segues work, and I couldn't find a simple way of doing a popover segue that would operate in the way I needed it to without building a custom UIStoryboardSegue subclass. This subclass doesn't do a lot, really, except REUSE your popover controller AND allow toggling.
Given that it became a custom subclass, I also couldn't get any custom information into it from the storyboard, so I put that code into the prepareForSegue: handler in the view controller.
This is what it looks like in Xcode:
What that picture shows is a custom segue going from a bar button item to a navigation controller. It's a navigation controller because there's a sequence of table view controllers under that popover, but it can be any subclass of UIViewController.
Here's the code:
SinglePopoverSegue.h
Code:
//
// SinglePopoverSegue.h
// LTE-A Visualizer
//
// Created by Ron Crocker on 1/24/12.
// Copyright (c) 2012 Nokia Siemens Networks, LLC. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface SinglePopoverSegue : UIStoryboardSegue
@property (strong) UIPopoverController *popoverController;
@property (strong) UIBarButtonItem *barButtonItem;
@property (assign) UIPopoverArrowDirection popoverArrowDirections;
@property (assign) BOOL animated;
@property (assign) BOOL toggleMode;
@end
SinglePopoverSegue.m
Code:
//
// SinglePopoverSegue.m
// LTE-A Visualizer
//
// Created by Ron Crocker on 1/24/12.
// Copyright (c) 2012 Nokia Siemens Networks, LLC. All rights reserved.
//
#import "SinglePopoverSegue.h"
@implementation SinglePopoverSegue
@synthesize popoverController;
@synthesize popoverArrowDirections;
@synthesize animated;
@synthesize barButtonItem;
@synthesize toggleMode;
-(id)initWithIdentifier:(NSString *)identifier source:(UIViewController *)source destination:(UIViewController *)destination
{
if ((self = [super initWithIdentifier:identifier
source:source
destination:destination])) {
self.popoverArrowDirections = UIPopoverArrowDirectionAny;
self.popoverController = nil;
self.animated = YES;
self.barButtonItem = nil;
self.toggleMode = YES;
}
return self;
}
-(void)perform
{
if (!self.popoverController.popoverVisible) {
self.popoverController.contentViewController = self.destinationViewController;
[self.popoverController presentPopoverFromBarButtonItem:self.barButtonItem
permittedArrowDirections:self.popoverArrowDirections
animated:self.animated];
} else if (self.toggleMode) {
[self.popoverController dismissPopoverAnimated:self.animated];
}
}
@end
The place where it's used in a view controller:
Code:
#pragma mark - UIStoryboard handlers
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"ConfigButton"]) {
UINavigationController *navController = segue.destinationViewController;
LAVSettingsController *vc = [navController.viewControllers objectAtIndex:0];
SinglePopoverSegue *popoverSegue = (SinglePopoverSegue *)segue;
if (!__popoverController) {
__popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverSegue.destinationViewController];
}
popoverSegue.barButtonItem = sender;
popoverSegue.popoverController = self.popoverController;
vc.popoverController = self.popoverController;
[self.popoverController setContentViewController:navController];
}
}
So you can see from the code in prepareForSegue: that I can't get enough information into the segue in IB, so I have to do it here. In particular, I can't get (or find) the "source" element, the place from which the popover originates, which is an important aspect of a UIPopoverController.
EDIT: it's not entirely obvious that __popoverController is the backing store for the popoverController property. It's got 2 underscores because UIViewController already has a property called _popoverController but I can't actually get access to that to store MY popover controller. This is probably a risky use of the name, but whatever. If it becomes a problem, I'll deal with it then.