16

I have a view controller that's presented in a popover using a storyboard segue.

enter image description here

In the presenting view controller, I had the following code:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let svc = segue.destinationViewController as? SettingsViewController {
        svc.popoverPresentationController?.delegate = self
    }
}

However, it turns out that the presented view controller, even though it appears as a popover, has a modalPresentationStyle of '.Modal, and hence a nil popoverPresentationController. Weird!

So, I updated the code as follows:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if let svc = segue.destinationViewController as? SettingsViewController {
        svc.modalPresentationStyle = .Popover
        svc.popoverPresentationController?.delegate = self
    }
}

The svc.popoverPresentationController delegate is now set OK, but if the popover is dismissed by the user tapping outside, none of the UIPopoverPresentationControllerDelegate delegate methods (e.g. popoverPresentationControllerShouldDismissPopover are called. What am I missing?

Ashley Mills
  • 50,474
  • 16
  • 129
  • 160

2 Answers2

7

No need for delegation in this case. If the presentingViewController (whatever vc is containing the popover) just overrides:

Swift 4

override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
    print("Dismiss: \(String(describing: self.presentedViewController))")
    super.dismiss(animated: flag, completion: completion)
}

Swift 3

override func dismissViewControllerAnimated(flag: Bool, completion: (() -> Void)?) {
    // Before calling super get a handle on which controller is being dismissed
    print("Dismiss: \(self.presentedViewController)")
    super.dismissViewControllerAnimated(flag, completion: completion)
}

You will get notified no matter how it is dismissed. You also do not need to set any additional variables/settings in the prepareForSegue: (at least to handle this interaction).

guidev
  • 2,695
  • 2
  • 23
  • 44
Firo
  • 15,448
  • 3
  • 54
  • 74
  • It's the only answer, so get the reward. Doesn't seem right though, somehow – Ashley Mills Feb 04 '16 at 17:35
  • @AshleyMills curious why you don't think so? With the move towards popovers, alerts, and action sheets being actual containers (starting in iOS 8), as opposed to their own independent view elements (e.g. windows), it actually really does make sense. A popover now functions the same as a normal VC. – Firo Feb 04 '16 at 17:39
  • Sorry, not in the sense that your was a bad answer. Just that I was hoping someone would know why the popoverPresentationControllerDelegate methods weren't getting fired. And in my case, the popover is presented from a UIBarButtonItem in the nav bar, so the navController needs subclassing to implement your solution – Ashley Mills Feb 04 '16 at 17:41
1

Ran into the same issue and after reading through the documentation, I realized that you need to call:

[self presentViewController:myPopoverViewController animated: YES completion: nil];

in order for the delegate methods to get called.

The full snippet is as follows and is run within my -(void)prepareForSegue:sender method:

// Present the view controller using the popover style.
myPopoverViewController.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:myPopoverViewController animated: YES completion: nil];

// Get the popover presentation controller and configure it.
UIPopoverPresentationController *presentationController =
         [myPopoverViewController popoverPresentationController];
presentationController.permittedArrowDirections =
         UIPopoverArrowDirectionLeft | UIPopoverArrowDirectionRight;
presentationController.sourceView = myView;
presentationController.sourceRect = sourceRect;

https://developer.apple.com/documentation/uikit/uipopoverpresentationcontroller

kartboy16
  • 11
  • 2