Swift中使用#selector调用带参数@objc函数报错的技术求助
解决Swift中#selector调用带参数函数的报错问题
这个报错的核心原因是你误解了#selector的用法——#selector只能引用方法的签名(也就是方法的名字和参数类型),不能直接传递具体的参数值,而且NSMenuItem的action方法默认需要接收一个sender参数(触发动作的菜单本身),你的原写法既不符合selector的语法要求,也不匹配NSMenuItem期望的action方法签名。
下面给你两种常用的解决方案:
方案一:利用NSMenuItem的representedObject传递参数
这是最灵活的方式,适合传递任意类型的参数(只要能桥接到Objective-C):
- 首先修改你的
changeCrypto方法,改成接收sender参数,并从中提取我们要的参数:
@objc func changeCrypto(_ sender: NSMenuItem) { // 从sender的representedObject中取出我们预先存储的加密货币字符串 guard let crypto = sender.representedObject as? String else { print("无法获取加密货币参数") return } // 在这里执行你的业务逻辑 print("切换到加密货币:\(crypto)") }
- 然后在构造菜单时,给每个NSMenuItem设置
representedObject:
func constructMenu() { let menu = NSMenu() // 创建Bitcoin菜单并绑定参数 let bitcoinItem = NSMenuItem(title: "Bitcoin", action: #selector(changeCrypto(_:)), keyEquivalent: "B") bitcoinItem.representedObject = "bitcoin" menu.addItem(bitcoinItem) // 创建Ethereum菜单并绑定参数 let ethereumItem = NSMenuItem(title: "Ethereum", action: #selector(changeCrypto(_:)), keyEquivalent: "E") ethereumItem.representedObject = "ethereum" menu.addItem(ethereumItem) // 创建Litecoin菜单并绑定参数 let litecoinItem = NSMenuItem(title: "Litecoin", action: #selector(changeCrypto(_:)), keyEquivalent: "L") litecoinItem.representedObject = "litecoin" menu.addItem(litecoinItem) menu.addItem(NSMenuItem.separator()) menu.addItem(NSMenuItem(title: "Quit It", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")) statusItem.menu = menu }
方案二:利用tag标记区分参数(适合有限固定选项)
如果你的加密货币选项是固定的,也可以用tag来区分:
- 先定义一个枚举对应不同的加密货币(用rawValue作为tag值):
enum CryptoType: Int { case bitcoin = 0 case ethereum = 1 case litecoin = 2 }
- 修改
changeCrypto方法,通过sender的tag判断对应的加密货币:
@objc func changeCrypto(_ sender: NSMenuItem) { guard let cryptoType = CryptoType(rawValue: sender.tag) else { print("无效的菜单标记") return } let cryptoString: String switch cryptoType { case .bitcoin: cryptoString = "bitcoin" case .ethereum: cryptoString = "ethereum" case .litecoin: cryptoString = "litecoin" } // 执行业务逻辑 print("切换到加密货币:\(cryptoString)") }
- 构造菜单时给每个item设置对应的tag:
func constructMenu() { let menu = NSMenu() let bitcoinItem = NSMenuItem(title: "Bitcoin", action: #selector(changeCrypto(_:)), keyEquivalent: "B") bitcoinItem.tag = CryptoType.bitcoin.rawValue menu.addItem(bitcoinItem) let ethereumItem = NSMenuItem(title: "Ethereum", action: #selector(changeCrypto(_:)), keyEquivalent: "E") ethereumItem.tag = CryptoType.ethereum.rawValue menu.addItem(ethereumItem) let litecoinItem = NSMenuItem(title: "Litecoin", action: #selector(changeCrypto(_:)), keyEquivalent: "L") litecoinItem.tag = CryptoType.litecoin.rawValue menu.addItem(litecoinItem) menu.addItem(NSMenuItem.separator()) menu.addItem(NSMenuItem(title: "Quit It", action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")) statusItem.menu = menu }
补充说明
你原来的代码中,#selector(changeCrypto(crypto: "bitcoin"))这种写法是错误的——#selector只需要指定方法的签名,比如#selector(changeCrypto(_:)),具体的参数要通过sender来传递,这是由Objective-C的消息发送机制决定的,因为菜单触发动作时,会把自身作为参数传递给action方法。
内容的提问来源于stack exchange,提问作者Oskar Sherrah
相关产品推荐
相关产品推荐

