Since the upgrade from iOS 15 to iOS 17, my iPad app has been crashing when I try to display modal popovers with the following error and I am unable to resolve the issue:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present modal view controller on itself. Presenting controller is <VolumeVC: 0x7fc81882c520>.'
For context, I've been using the following utility class throughout my app to first get the top most view controller in the window so that I can then display a modal popover with a view controller in it.
Utility.m
+ (UIViewController*)topViewController {
UIViewController *topVC = [[UIApplication sharedApplication] keyWindow].rootViewController;
NSLog(@"Utility::topViewController(): topVC is: %@", topVC);
int countLoops = 0;
while (topVC.presentedViewController != nil) {
topVC = topVC.presentedViewController;
NSLog(@"Utility::topViewController(): In loop, topVC is: %@, countLoops is: %i", topVC, countLoops);
countLoops++;
if (countLoops > 25) { break; }
}
return topVC;
}
+ (void)showDialogiPad:(UIViewController *)contentVC
fromPresentingVC:(UIViewController *)presentingVC
inView:(UIView *)view
atFrame:(CGRect)frame
withDirection:(UIPopoverArrowDirection)direction {
// Choose the presentation style in which the content is displayed in a popover view
contentVC.modalPresentationStyle = UIModalPresentationPopover;
// Set the popover size, anchor location and direction
contentVC.popoverPresentationController.sourceRect = frame;
contentVC.popoverPresentationController.sourceView = view;
contentVC.popoverPresentationController.permittedArrowDirections = direction;
// Set the arrow direction for the popover
popoverVC.permittedArrowDirections = direction;
// Present the popover presentation controller
[presentingVC presentViewController:contentVC animated:YES completion:nil];
}
An example of how this gets called from elsewhere in the code is the following:
// Show the volume view controller in a popover
[Utility showDialogiPad:volumeVC // volumeVC is a simple view controller I want to show in the popup
fromPresentingVC:[Utility topViewController]
inView:view
atFrame:frame
withDirection:UIPopoverArrowDirectionAny];
A few notes:
- This code will work 1 to N times of opening & closing the popover but it will always eventually crash as of iOS 17. The crash always seems to happen when I open and close the popover quickly in succession.
frame
andview
are always populated with the correct values, andvolumeVC
andpresentingVC
are always non-nil when I print them out in theUtility::showDialogiPad
dialog method.- When it crashes, the output of the debug statements in
+ (UIViewController*)topViewController
are:
Utility::topViewController(): topVC is: <UITabBarController: 0x7fc22d81ae00>
Utility::topViewController(): In loop, topVC is: <VolumeVC: 0x7fc22d01f460>, countLoops is: 0
- The main window of the app is a UITabBarController with a UISplitViewController in each tab.
- This app does not have multiple scenes in it nor does it use UIWindowScene.
- I know
keyWindow
is deprecated as of iOS 13. When I replace thetopViewController
code with the following:
+ (UIViewController*)topViewController {
UIWindowScene *windowScene = (UIWindowScene *)[UIApplication sharedApplication].connectedScenes.allObjects.firstObject;
UIViewController *topVC = windowScene.windows.firstObject.rootViewController;
return topVC;
}
It will work 1 to N times but eventually it will crash with this error:
*** Terminating app due to uncaught exception 'NSGenericException', reason: 'UIPopoverPresentationController (<UIPopoverPresentationController: 0x7ff05c156890>) should have a non-nil sourceView or barButtonItem set before the presentation occurs.'
Thanks for any assistance with this.