Search code examples
iosuialertcontrollermac-catalyst

Can't dismiss alerts programmatically in Mac Catalyst?


I'm showing an alert like this:

self.connectingAlert = [UIAlertController
    alertControllerWithTitle:@""
    message:NSLocalizedString(@"CONNECTING", nil)
    preferredStyle:UIAlertControllerStyleAlert];
[self.connectingAlert addAction:[UIAlertAction
    actionWithTitle:NSLocalizedString(@"BUTTON_CANCEL", nil)
    style:UIAlertActionStyleCancel
    handler:^(UIAlertAction *action) {
        [self cancelRequest];
    }]];
[self presentViewController:self.connectingAlert animated:TRUE completion:nil];

Then later I want to dismiss the alert programmatically like this:

[self dismissViewControllerAnimated:FALSE completion:nil];

The dismiss code works fine in iOS, but does nothing in Mac Catalyst. This might have something to do with the fact that alerts are presented as a part of the app window, sort of outside of the app, and the presentation style is ignored. But I would expect the dismiss method to still affect the Mac alerts.

I tried this to make sure everything is hooked up correctly:

UIViewController *test1 = self.connectingAlert.presentingViewController;
UIViewController *test2 = self.connectingAlert.presentingViewController.presentedViewController;

test1 returns the navigation controller that the view controller is part of, which seems odd, but it does the same thing on iOS. test2 returns my alert. Just to make sure, I tried this code, but it doesn't work either:

[self.connectingAlert.presentingViewController dismissViewControllerAnimated:FALSE completion:nil];

Does anyone have experience with this? I don't see anything about it in the documentation.


Solution

  • It turns out that while you're supposed to send the dismiss message to the presenting (parent) view controller...

    [self dismissViewControllerAnimated:FALSE completion:nil];
    

    ...I have to send the dismiss message to the alert instead, and then it dismisses:

    [self.connectingAlert dismissViewControllerAnimated:FALSE completion:nil];
    

    The documentation for dismissViewControllerAnimated says:

    The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, UIKit asks the presenting view controller to handle the dismissal.

    I think what this means is that Mac Catalyst is doing something funny with the connection between the presenting and the presented view controller. If I check self.presentedViewController, that gives me the UIAlertController. But if I call self dismiss dismissViewControllerAnimated..., nothing happens, as if there is no presented view controller. But if I call self.connectingAlert dismissViewControllerAnimated..., the dismiss method somehow finds its way to the real presenting view controller. I'll report this as a bug to Apple.

    Meanwhile, I'm happy to have a workaround.