Search code examples
nsmenuitemfindersync

FinderSync context menu items beep, never call action


I want to generate a menu which will call functions on a class other than that one which generated the menu, and then place that in Finder. However, when I click the menu item, the system error beep plays and my function is never called.

Here's a SSCCE:

import Cocoa
import FinderSync



@objc(FinderSync)
class FinderSync: FIFinderSync {

    var observedFolder = URL(fileURLWithPath: "/")


    override init() {
        super.init()

        NSLog("\(FinderSync.self.className()) launched from \(Bundle.main.bundlePath)")

        // Set up the directory we are syncing.
        FIFinderSyncController.default().directoryURLs = [self.observedFolder]
    }



    // MARK: - Menu and toolbar item support

    override var toolbarItemName: String {
        return "Wonderful Test App"
    }


    override var toolbarItemToolTip: String {
        return "This is wonderful"
    }


    override var toolbarItemImage: NSImage {
        return NSImage(named: NSImage.cautionName)!
    }


    override func menu(for menuKind: FIMenuKind) -> NSMenu {
        let menu = NSMenu(title: "")
        let menuItem = NSMenuItem(title: "Click me!", action: #selector(SomeOtherClass.remoteAction), keyEquivalent: "")
        menuItem.target = SomeOtherClass.shared
        menuItem.action = #selector(SomeOtherClass.remoteAction)
        menu.addItem(menuItem)
        return menu
    }
}



@objc(SomeOtherClass)
public class SomeOtherClass: NSObject {

    public static let shared = SomeOtherClass()


    deinit {
        NSLog("Deallocated!")
        preconditionFailure("Shared instance should never be deallocated!")
    }


    @IBAction
    @objc(remoteAction:)
    public func remoteAction(_ sender: Any?) {
        NSLog("Remote!")
    }
}

I've verified via the memory debugger that SomeOtherClass.shared is still in memory before, during, and after the menu item is clicked, so it's not being deallocated or anything.


Solution

  • It appears you can't add actions which are within any class other than your FinderSync extension's principal class. Which is about as stupid as everything else about NSMenuItem, so I'm not surprised.

    So, you'll have to move the action(s) into your FinderSync class, despite how ugly that might be for organization.