You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中使用#selector调用带参数@objc函数报错的技术求助

解决Swift中#selector调用带参数函数的报错问题

这个报错的核心原因是你误解了#selector的用法——#selector只能引用方法的签名(也就是方法的名字和参数类型),不能直接传递具体的参数值,而且NSMenuItem的action方法默认需要接收一个sender参数(触发动作的菜单本身),你的原写法既不符合selector的语法要求,也不匹配NSMenuItem期望的action方法签名。

下面给你两种常用的解决方案:

方案一:利用NSMenuItem的representedObject传递参数

这是最灵活的方式,适合传递任意类型的参数(只要能桥接到Objective-C):

  1. 首先修改你的changeCrypto方法,改成接收sender参数,并从中提取我们要的参数:
@objc func changeCrypto(_ sender: NSMenuItem) {
    // 从sender的representedObject中取出我们预先存储的加密货币字符串
    guard let crypto = sender.representedObject as? String else {
        print("无法获取加密货币参数")
        return
    }
    // 在这里执行你的业务逻辑
    print("切换到加密货币:\(crypto)")
}
  1. 然后在构造菜单时,给每个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来区分:

  1. 先定义一个枚举对应不同的加密货币(用rawValue作为tag值):
enum CryptoType: Int {
    case bitcoin = 0
    case ethereum = 1
    case litecoin = 2
}
  1. 修改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)")
}
  1. 构造菜单时给每个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 04:03:27