56

I have the code to create and NSAlert in Objective-C but I would now like to create it in Swift.

The alert is to confirm that the user would like to delete a document.

I would like the "delete" button to then run the delete function and the "cancel" one just to dismiss the alert.

How can I write this in Swift?

NSAlert *alert = [[[NSAlert alloc] init] autorelease];
[alert addButtonWithTitle:@"Delete"];
[alert addButtonWithTitle:@"Cancel"];
[alert setMessageText:@"Delete the document?"];
[alert setInformativeText:@"Are you sure you would like to delete the document?"];
[alert setAlertStyle:NSWarningAlertStyle];
[alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
pkamb
  • 33,281
  • 23
  • 160
  • 191
Tom Coomer
  • 6,227
  • 12
  • 45
  • 82
  • You might want to consider that `beginSheetModal(for:completionHandler:)` is *not* deprecated, in fact it may be the more desirable way to handle your modal dialog (in a block). It would also be closer to the old way with the `didEndSelector` and it won't stop the whole application. – Patru Jul 01 '17 at 13:30

6 Answers6

153

beginSheetModalForWindow:modalDelegate is deprecated in OS X 10.10 Yosemite.

Swift 2

func dialogOKCancel(question: String, text: String) -> Bool {
    let alert: NSAlert = NSAlert()
    alert.messageText = question
    alert.informativeText = text
    alert.alertStyle = NSAlertStyle.WarningAlertStyle
    alert.addButtonWithTitle("OK")
    alert.addButtonWithTitle("Cancel")
    let res = alert.runModal()
    if res == NSAlertFirstButtonReturn {
        return true
    }
    return false
}

let answer = dialogOKCancel("Ok?", text: "Choose your answer.")

This returns true or false according to the user's choice.

NSAlertFirstButtonReturn represents the first button added to the dialog, here the "OK" one.

Swift 3

func dialogOKCancel(question: String, text: String) -> Bool {
    let alert = NSAlert()
    alert.messageText = question
    alert.informativeText = text
    alert.alertStyle = NSAlertStyle.warning
    alert.addButton(withTitle: "OK")
    alert.addButton(withTitle: "Cancel")
    return alert.runModal() == NSAlertFirstButtonReturn
}

let answer = dialogOKCancel(question: "Ok?", text: "Choose your answer.")

Swift 4

We now use enums for the alert's style and the button selection.

func dialogOKCancel(question: String, text: String) -> Bool {
    let alert = NSAlert()
    alert.messageText = question
    alert.informativeText = text
    alert.alertStyle = .warning
    alert.addButton(withTitle: "OK")
    alert.addButton(withTitle: "Cancel")
    return alert.runModal() == .alertFirstButtonReturn
}

let answer = dialogOKCancel(question: "Ok?", text: "Choose your answer.")
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
  • 4
    Make sure to `import AppKit` (at least in swift 3) – Claude Feb 03 '17 at 11:50
  • 2
    @Claude If you're making an alert it means you're making a Cocoa app and it means you're importing Cocoa which already imports AppKit. – Eric Aya Feb 03 '17 at 12:09
  • Possibly I shouldn't fire the alert from a non-VC class; but I just wanted some poor-man's error-display. This util class didn't import anything but Foundation, so I needed the import (at least it made XCode happy). – Claude Feb 03 '17 at 12:22
  • @Claude Oh, I see. You're right to manually import AppKit in that case - sorry for the confusion. – Eric Aya Feb 03 '17 at 12:27
  • 1
    `alert.alertStyle = .warning` works in Swift 3 too, no need to add `NSAlertStyle ` – zxcat Jul 05 '17 at 13:01
  • @MCCCS You're using the Swift 4 example but it looks like you should be using the Swift 3 one. – Eric Aya Aug 03 '17 at 11:06
  • Although `beginSheetModalForWindow:modalDelegate` is indeed deprecated in OS X 10.10 Yosemite, a non-deprecated equivalent, [`beginSheetModal(for:completionHandler:)`](https://developer.apple.com/documentation/appkit/nsalert/1524296-beginsheetmodal) is still perfectly usable. – Jamie Birch Jun 30 '18 at 13:05
  • @EricAya How do I do this returning the text of the button clicked? – Revel Carlberg West May 04 '21 at 14:56
26

I think this may work for you...

let a = NSAlert()
a.messageText = "Delete the document?"
a.informativeText = "Are you sure you would like to delete the document?"
a.addButtonWithTitle("Delete")
a.addButtonWithTitle("Cancel")
a.alertStyle = NSAlert.Style.WarningAlertStyle

a.beginSheetModalForWindow(self.view.window!, completionHandler: { (modalResponse) -> Void in
    if modalResponse == NSAlertFirstButtonReturn {
        print("Document deleted")
    }
})
Ram Patra
  • 16,266
  • 13
  • 66
  • 81
Jose Hidalgo
  • 421
  • 4
  • 8
11

Updated Jose Hidalgo's answer for Swift 4:

let a: NSAlert = NSAlert()
a.messageText = "Delete the document?"
a.informativeText = "Are you sure you would like to delete the document?"
a.addButton(withTitle: "Delete")
a.addButton(withTitle: "Cancel")
a.alertStyle = NSAlert.Style.warning

a.beginSheetModal(for: self.window!, completionHandler: { (modalResponse: NSApplication.ModalResponse) -> Void in
    if(modalResponse == NSApplication.ModalResponse.alertFirstButtonReturn){
        print("Document deleted")
    }
})
Jamie Birch
  • 5,839
  • 1
  • 46
  • 60
5

opt @Jose Hidalgo's answer for Swift 5

        let a = NSAlert()
        a.messageText = "Delete the document?"
        a.informativeText = "Are you sure you would like to delete the document?"
        //   .alertFirstButtonReturn
        a.addButton(withTitle: "Delete")

        //   .alertSecondButtonReturn
        a.addButton(withTitle: "Cancel")
        a.alertStyle = .warning
        var w: NSWindow?
        if let window = view.window{
            w = window
        }
        else if let window = NSApplication.shared.windows.first{
            w = window
        }
        if let window = w{
            a.beginSheetModal(for: window){ (modalResponse) in
                if modalResponse == .alertFirstButtonReturn {
                    print("Document deleted")
                }
            }
        }
dengST30
  • 3,643
  • 24
  • 25
0

I tried above solutions but I was not able to get proper size of alert. I have defined size of alert too.

        let alert = NSAlert()
        alert.messageText = "YOUR MESSAGE"
        alert.addButton(withTitle: "BUTTON1")
        alert.addButton(withTitle: "BUTTON2")
        var frame = alert.window.frame
        frame.size.height = 300
        frame.size.width = 200
        alert.window.setFrame(frame, display: true)
        
        let stackViewer = NSStackView(frame: NSRect(x: 0, y: 0, width: 200, height: 00))
        alert.accessoryView = stackViewer
        
        
        alert.beginSheetModal(for: self.view.window!, completionHandler: { (modalResponse) -> Void in
                if modalResponse == NSApplication.ModalResponse.alertFirstButtonReturn {
                    print("first btn")
                    
                }else{
                    print("second btn")
              
            }
        })
Lakshmi Yadav
  • 156
  • 1
  • 10
0
    let anAlert = NSAlert()
    anAlert.messageText = "Exit?"
    anAlert.informativeText = "Changes will not be saved!"
    anAlert.alertStyle = .warning
    anAlert.addButton(withTitle: "Yes")
    anAlert.addButton(withTitle: "No")
    if anAlert.runModal() == .alertFirstButtonReturn {
        return .terminateNow
    }
    return .terminateLater
Mateus
  • 357
  • 1
  • 4
  • 14