Most of these options went slightly above my head, because I'm trying very hard to keep as much of my segue logic in the storyboard rather than in code, and I don't have good sample code to work from (stackoverflow tends to favor pre-iOS-9). For example, I couldn't figure out how to make my source view controller a presentation controller delegate for the segue in the storyboard; perhaps I still have a lot to learn about storyboards.
What I wound up doing instead was, to forget about adaptive presentations, always embed in a navigation controller and conditionally add a Done button on the target view controller in prepareForSegue, when the source controller is horizontal size class Compact:
class MyViewController {
func dismissCompactPopoverPresentationController() {
self.dismissViewControllerAnimated(true, completion: nil)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "myPopoverSegue" {
let navigationController = segue.destinationViewController as! UINavigationController
let myDestinationViewController = navigationController.topViewController as! MyDestinationViewController
// Other segue setup for my destination view controller
if self.traitCollection.horizontalSizeClass == .Compact {
myDestinationViewController.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismissCompactPopoverPresentationController")
}
}
}
}
This appears to work for the use case where I have a modal destination view controller and want to "escape" out of it, either by tapping outside of the popover in Regular size class, or by tapping Done in the navigation controller in Compact size class. I haven't tried to solve the "would prefer a push instead of a modal popver" use case (I might abandon that in my UI now that I have the above workaround).