How to Change the Detail of a UISplitViewController in the Background

A UISplitViewController has a master and a detail view controller. When the selected item is deleted and the detail is visible, you can perform a segue. If the detail is not visible, performing a segue to change the detail will present it.

I didn’t want that.

There are two cases where you will want to change the detail although it’s not visible:

Both have in common that the horizontal size class can become “compact” (UIUserInterfaceSizeClassCompact) and that this isn’t fixed per device anymore but may change over time.

Let’s say you invoke -displayNoSelectionDetailScene from your master’s -tableView:commitEditingStyle:forRowAtIndexPath:, that is when the user deletes an item from the table view. If the deleted item is the same as the currently selected one, you have to “close” the detail view in order to not present stale data.

So here is my displayNoSelectionDetailScene implementation:

- (void)displayNoSelectionDetailScene
    if (!self.splitViewController.collapsed) {
        // Show empty selection detail only when the detail is visible.
        [self performSegueWithIdentifier:kDetailSegueNoSelection sender:self];
    } else {

        UINavigationController *emptyNC = [self.storyboard 
        // I'm so used to unwrapping nil that I get paranoid ...
        assert(emptyNC != nil);  
        self.splitViewController.viewControllers = 
            @[self.splitViewController.viewControllers.firstObject, emptyNC];

If the UISplitViewController is collapsed, the view controller or the whole app has a compact horizontal size class, for example when the iPhone 6 Plus is rotated to portrait.

At first I thought I should hook in to -willTransitionToTraitCollection:withTransitionCoordinator: and reset the detail view controller when the horizontal size class changes – but the results were weird. Upon every table view selection did the trait collection reported a change from compact to regular:

- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
    if (self.traitCollection.horizontalSizeClass == UIUserInterfaceSizeClassCompact 
        && newCollection.horizontalSizeClass == UIUserInterfaceSizeClassRegular) {
        // Dismiss previously open details in the background
        [self displayNoSelectionDetailScene];

Didn’t work.

Quickly replacing the view controllers of the UISplitViewController when in a collapsed state does.

Browse the blog archive