NSMenu的触发方法应在哪里声明?自定义类中方法不生效问题
问题原因
- 你创建菜单项时仅指定了
action选择子,没有手动设置对应的target,AppKit默认会沿着应用响应链查找可响应该方法的对象,你的自定义RightClickMenu类/实例不在响应链中,系统判定无响应者,所以菜单项置灰不可点击。 - 你的
RightClickMenu没有继承NSObject,不支持OC Runtime的消息派发机制,即便系统找到了该类也无法触发标记了@objc的方法。 - 你当前的
test是实例方法,但你通过静态方法createMenu创建菜单时,没有生成并持有RightClickMenu的实例,即便设置了target也会因为实例被释放导致方法无法触发。
解决方案
方案1:将触发方法改为类方法,target设为类本身
适合不需要维护状态的简单菜单逻辑:
// 必须继承NSObject才能支持OC Runtime的消息派发 class RightClickMenu: NSObject { static func createMenu() -> NSMenu { let menu = NSMenu(title: "Status Bar Menu") let item = menu.addItem( withTitle: "Test", action: #selector(test(_:)), keyEquivalent: "" ) // 手动指定target为当前类 item.target = RightClickMenu.self return menu } // 改为类方法 @objc class func test(_ sender: Any?){ print("Test") } }
方案2:生成单例实例持有,target设为单例
适合需要维护菜单相关状态的场景,避免实例被释放:
class RightClickMenu: NSObject { // 全局单例,保证实例不被释放 static let shared = RightClickMenu() static func createMenu() -> NSMenu { let menu = NSMenu(title: "Status Bar Menu") let item = menu.addItem( withTitle: "Test", action: #selector(shared.test(_:)), keyEquivalent: "" ) // 指定target为单例实例 item.target = shared return menu } // 保持实例方法即可 @objc func test(_ sender: Any?){ print("Test") // 可以在这里维护实例属性状态 } }
补充说明:AppKit中所有基于action-target机制的控件(NSMenuItem、NSButton等)如果不手动指定target,都会默认走响应链查找响应者,只有响应链上的对象(NSViewController、NSView、NSWindow、NSApp、AppDelegate这些默认在响应链里的对象)的方法能被自动找到,自定义类如果不在响应链里必须手动指定target才能触发方法。
内容的提问来源于stack exchange,提问作者Willey3x37
相关产品推荐
相关产品推荐

