swiftmacoscocoansalert

Check if NSAlert is currently showing up


I am using an NSAlert to display error messages on the main screen of my app. Basically, the NSAlert is a property of my main view controller

class ViewController: NSViewController {

    var alert: NSAlert?

    ...

}

And when I receive some notifications, I display some messages

func operationDidFail(notification: NSNotification)
{
    dispatch_async(dispatch_get_main_queue(), {

        self.alert = NSAlert()
        self.alert.messageText = "Operation failed"
        alert.runModal();
    })
}

Now, if I get several notifications, the alert shows up for every notification. I mean, it shows up with the first message, I click on "Ok", it disappears and then shows up again with the second message etc... Which is a normal behaviour.

What I would like to achieve is to avoid this sequence of error message. I actually only care about the first one. Is there a way to know if my alert view is currently being displayed ? Something like alert.isVisible as on iOS's UIAlertView ?


Solution

  • From your code, I suspect that notification is triggered in background thread. In this case, any checks that alert is visible right now will not help. Your code will not start subsequent block execution until first block will finish, because runModal method will block, running NSRunLoop in modal mode.

    To fix your problem, you can introduce atomic bool property and check it before dispatch_async.

    Objective-C solution:

    - (void)operationDidFail:(NSNotification *)note {
        if (!self.alertDispatched) {
            self.alertDispatched = YES;
            dispatch_async(dispatch_get_main_queue(), ^{
                self.alert = [NSAlert new];
                self.alert.messageText = @"Operation failed";
                [self.alert runModal];
                self.alertDispatched = NO;
            });
        }
    }
    

    Same code using Swift:

    func operationDidFail(notification: NSNotification)
    {
        if !self.alertDispatched {
            self.alertDispatched = true
            dispatch_async(dispatch_get_main_queue(), {
                self.alert = NSAlert()
                self.alert.messageText = "Operation failed"
                self.alert.runModal();
                self.alertDispatched = false
            })
        }
    }