Search code examples
swiftmacosnsalert

Why is it that after showing an NSAlert nothing works?


Why is it that after showing an NSAlert nothing works until I close the NSAlert?

I was trying to print a statement after the display of an NSAlert but print is not working.

Below I have attached my code:

let alert: NSAlert = NSAlert()
alert.messageText = "Hello I am Message text"
alert.informativeText = "i am information"
alert.addButton(withTitle: "OK") // First Button
alert.addButton(withTitle: "Cancel") // 2nd Button
alert.alertStyle = NSAlert.Style.warning

alert.delegate = self
if alert.runModal() == .alertFirstButtonReturn {
    print("First Button clicked")
} else {
    print("Cancel button clicked")
}

print("after NSAlert >>>>>>> ")

enter image description here


Solution

  • My question is why.

    Notice how runModal returns the result of the modal as a NSModalResponse. Code after the line alert.runModal() must be able to access the value that it returns, e.g.

    let result = alert.runModal()
    print(result)
    

    If the code after runModal were run as soon as the modal is displayed, what would result be? The user has not clicked any buttons on the modal yet, so no one knows!

    This is why when runModal is called, code execution kind of just pauses there, at that line, until the user chooses one of the options. runModal is synchronous and blocking.

    Compare this with alert.beginSheetModal, which accepts a completionHandler closure, and the modal response is not returned, but passed to the completionHandler. This allows the code after the call to continue to run while the modal is presented, because the code after the call does not have access to the modal response. Only the code in the completionHandler does. beginSheetModal is asynchronous.


    If you have something you want to print as soon as the alert is displayed, write it before the runModal call, and (optionally) wrap it in a DispatchQueue.asyncAfter/DispatchQueue.async call, so that your print is asynchronous.

    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) {
        print("Hello")
    }
    alert.runModal()