On iPadOS 17, a crash occurs when dismissing a popover and then quickly presenting one again. Usually the error is the following:
UIPopoverPresentationController should have a non-nil sourceView or barButtonItem set before the presentation occurs
However I've occasionally seen the following:
Application tried to present modally a view controller that is already being presented by the [main view controller]
This is the minimal source code necessary to reproduce this crash:
class ViewController: UIViewController {
let popoverVC = UIViewController()
@IBOutlet var showPopoverButton: UIButton!
@IBAction func showPopoverTapped(_ sender: UIButton) {
popoverVC.modalPresentationStyle = .popover
popoverVC.popoverPresentationController?.sourceView = showPopoverButton
present(popoverVC, animated: true)
}
}
Some additional things to consider about this issue:
.sourceRect
on the popoverPresentationController
has no effect.frame
or preferredContentSize
of the popover has no effect.guard
before presenting to make sure the sourceView
is not nil
but it has no effect.This issue seems to occur because the popover view controller isn't being fully de-allocated from memory when a new popover is being presented. This is creating some sort of collision. I've had success swizzling UIPopoverPresentationController.dismissalTransitionWillBegin
and I'd be happy to post that solution, but first I'd like to see if there are less hacky workarounds. I do not want to simply override dismissalTransitionWillBegin
because I want the default behaviour and would rather not rewrite my own popover animations just to satisfy this bug.
I get the same crash on iPadOS 17 too. It doesn't happen all the time so it's tricky why this happens.
My current workaround is to guard check if the current view controller is presenting another view controller, before going ahead and present a new one. So far this seems to work for me.
guard self.presentedViewController == nil else { return }