Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 ?

like image 533
Randy Avatar asked Dec 07 '25 08:12

Randy


2 Answers

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
        })
    }
}
like image 177
Borys Verebskyi Avatar answered Dec 10 '25 01:12

Borys Verebskyi


Instead of run modal you could try

- beginSheetModalForWindow:completionHandler:

source: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSAlert_Class/#//apple_ref/occ/instm/NSAlert/beginSheetModalForWindow:completionHandler:

In the completion handler set the alert property to nil. And only show the alert if the alert property is nil ( which would be every first time after dismissing the alert). EDIT : I don't see the documentation say anything about any kind of flag you look for.

like image 36
Raica Dumitru Cristian Avatar answered Dec 10 '25 00:12

Raica Dumitru Cristian