Swift中如何创建Selector类型数组适配addTarget的action参数
嘿,我来帮你搞定这个在Swift中用for循环创建按钮并绑定Selector的问题!
首先,咱们先理清核心问题:addTarget的action参数要求是Selector类型,所以你需要创建的数组类型应该是[Selector],而不是字符串数组或者其他类型。下面一步步给你讲清楚解决方案和之前错误的原因:
一、正确的Selector数组实现方式
1. 先定义所有需要的@objc方法
因为Selector只能指向被@objc标记的方法(Swift方法默认不暴露给Objective-C运行时),所以先把你的segue方法加上@objc修饰:
@objc func segueToDice1() { performSegue(withIdentifier: "Dice1Segue", sender: self) } @objc func segueToDice2() { performSegue(withIdentifier: "Dice2Segue", sender: self) } @objc func segueToDice3() { performSegue(withIdentifier: "Dice3Segue", sender: self) }
2. 创建Selector数组
直接用#selector()语法把每个方法转换成Selector,存入数组:
let selectorArray: [Selector] = [ #selector(segueToDice1), #selector(segueToDice2), #selector(segueToDice3) ]
3. 在for循环中绑定按钮与Selector
遍历数组给每个自定义按钮设置addTarget:
for (index, selector) in selectorArray.enumerated() { let button = CustomButton() // 你的自定义按钮实例 // 设置按钮位置、样式等属性 button.frame = CGRect(x: 20, y: 100 + index * 60, width: 200, height: 50) button.setTitle("跳转至骰子\(index+1)", for: .normal) // 绑定点击事件 button.addTarget(self, action: selector, for: .touchUpInside) view.addSubview(button) }
二、解释你之前遇到的错误
1. 字符串数组报错的原因
addTarget的action参数需要的是Selector类型,直接传String会触发类型不匹配错误。虽然可以用Selector("segueToDice1")这种方式把字符串转成Selector,但这种方法不安全——编译器不会检查方法是否存在,一旦方法名写错或者被删除,运行时会崩溃,所以强烈推荐用#selector()语法,它是类型安全的。
2. [(Void)]数组报错的原因
[(Void)]等价于[Void],也就是空元组的数组,而你的segueToDice1是() -> ()类型的闭包,两者完全不是一回事,所以无法赋值。而且闭包也不能直接作为addTarget的action参数,因为addTarget依赖Objective-C运行时,只能识别标记为@objc的方法对应的Selector。
三、更简洁的优化方案(推荐)
如果你的按钮只是触发不同的segue,其实不需要写多个重复的方法,只需要给自定义按钮加一个存储segue标识符的属性,然后用一个通用的点击处理方法即可:
1. 给自定义按钮添加属性
class CustomButton: UIButton { var segueIdentifier: String? // 存储对应的segue标识符 }
2. 编写通用的点击处理方法
@objc func handleButtonTap(_ sender: CustomButton) { guard let identifier = sender.segueIdentifier else { return } performSegue(withIdentifier: identifier, sender: sender) }
3. 用标识符数组创建按钮
let segueIdentifiers = ["Dice1Segue", "Dice2Segue", "Dice3Segue"] for (index, identifier) in segueIdentifiers.enumerated() { let button = CustomButton() button.frame = CGRect(x: 20, y: 100 + index * 60, width: 200, height: 50) button.setTitle("跳转至骰子\(index+1)", for: .normal) button.segueIdentifier = identifier button.addTarget(self, action: #selector(handleButtonTap(_:)), for: .touchUpInside) view.addSubview(button) }
这个方案更简洁,避免了重复代码,也更易维护。
内容的提问来源于stack exchange,提问作者JeremyRaven

