4

I have a simple one file menu bar app in swift:

import Cocoa

class StatusBarApp : NSObject {

  func buildMenu() {
    let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)
    statusItem.title = "StatusBarApp"

    let menu = NSMenu()

    let aboutMenuItem = NSMenuItem()
    aboutMenuItem.title = "About"
    aboutMenuItem.target = self
    aboutMenuItem.action = #selector(about)
    menu.addItem(aboutMenuItem)

    statusItem.menu = menu
  }

  func about() {
    print("XXX")
  }
}

NSApplication.sharedApplication()
StatusBarApp().buildMenu()
NSApp.run()

I can't make the "About" menu bar item to connected to the about() function. When I run the app, the "About" item is disabled.

How do I pass the selector to menu item action in Swift 2.2? Thanks

lutrekubej
  • 63
  • 1
  • 3

3 Answers3

1

The selector is supposed to have a parameter (the NSMenuItem instance)

aboutMenuItem.action = #selector(StatusBarApp.about(_:))

...

func about(sender : NSMenuItem) {
   print("XXX")
}

Edit:

The solution is to run the app as full Cocoa app including its delegate.
I added a second menu item to terminate the app.

import Cocoa

class StatusBarApp : NSObject, NSApplicationDelegate {

  var statusItem : NSStatusItem!

  func applicationDidFinishLaunching(aNotification: NSNotification) {
    statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)
    statusItem.title = "StatusBarApp"

    let menu = NSMenu()

    let aboutMenuItem = NSMenuItem(title:"About", action:#selector(StatusBarApp.about(_:)), keyEquivalent:"")
    aboutMenuItem.target = self
    let quitMenuItem = NSMenuItem(title:"Quit", action:#selector(StatusBarApp.quit(_:)), keyEquivalent:"")
    quitMenuItem.target = self
    menu.addItem(aboutMenuItem)
    menu.addItem(quitMenuItem)

    statusItem.menu = menu
  }

  func about(sender : NSMenuItem) {
    print("XXX")
  }

  func quit(sender : NSMenuItem) {
    NSApp.terminate(self)
  }
}

NSApplication.sharedApplication()
let statusBarApp = StatusBarApp()
NSApp.delegate = statusBarApp
NSApp.run()
vadian
  • 274,689
  • 30
  • 353
  • 361
  • Thanks, I tried this change, but it didn't have any affect. The item was still disabled. If I enabled it with `menu.autoenablesItems = false`, the about function was not executed. – lutrekubej Apr 19 '16 at 12:35
  • I edited the answer. Thanks for pointing out the idea to run an application from a simple Swift file – vadian Apr 19 '16 at 12:56
  • Thank you! I was inspired by this: http://czak.pl/2015/09/23/single-file-cocoa-app-with-swift.html – lutrekubej Apr 19 '16 at 13:07
  • I read this article, too, to find out how to handle the Swift file – vadian Apr 19 '16 at 13:11
  • 1
    One thing to note is that whatever the target is. **It needs to be referenced strongly somewhere.** If the object is not in memory, it can not be referenced and therefore can not be accessed. – leogdion Dec 07 '16 at 18:34
0

update action

aboutMenuItem.action = Selector("about")

and add

aboutMenuItem.enabled = true
Rahul
  • 347
  • 3
  • 11
  • Thanks, but it doesn't work. It shows a warning: `warning: use '#selector' instead of explicitly constructing a 'Selector'` But more importantly, the item is still disabled, even after adding `aboutMenuItem.enabled = true` – lutrekubej Apr 19 '16 at 12:23
  • `aboutMenuItem.enabled = true` has no effect in this case, because the implicit validation has a higher priority. – vadian Apr 19 '16 at 12:29
0

Consider this:

import Cocoa

class StatusBarApp : NSObject {

    func buildMenu() {
        let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength)
        statusItem.title = "StatusBarApp"

        let menu = NSMenu()

        let aboutMenuItem = NSMenuItem()
        aboutMenuItem.title = "About"
        aboutMenuItem.target = self
        aboutMenuItem.action = #selector(about)
        menu.addItem(aboutMenuItem)

        statusItem.menu = menu
    }

    func about() {
        print("XXX")
    }
}


let app = StatusBarApp()
NSApplication.sharedApplication()
app.buildMenu()
NSApp.run()
Igor B.
  • 2,219
  • 13
  • 17
  • Thanks, this makes the "About" item enabled, but clicking on it doesn't execute the about function. – lutrekubej Apr 19 '16 at 12:32
  • I have updated the answer. That works fine for me. Apparently the reason is memory management. I logged deinit of StatusBarApp object and identified that the app object is destructed immediately in your case. – Igor B. Apr 19 '16 at 13:06
  • Thank you! I already selected a different answer with different solution, but this also works. – lutrekubej Apr 19 '16 at 13:10
  • Welcome :) @vadian It makes sense to point out that app delegate setting does not matter. The root cause is in memory management. – Igor B. Apr 19 '16 at 13:14