iOS开发:如何为@objc函数传递参数?(TableView按钮场景)
如何在@objc函数中传递邮箱地址给代理方法?
你遇到的问题本质是:Swift中#selector的写法不支持直接传递参数值,因为@objc方法的选择器是基于Objective-C的机制,它只能指定方法的签名(比如带不带sender参数),没法把具体的字符串值直接嵌进去。下面给你几种实用的解决方案:
方案一:利用按钮的title获取邮箱(最简单)
既然按钮上显示的就是邮箱地址,那我们可以在点击方法里直接从按钮的titleLabel中拿到这个值:
首先修改你添加target的代码,去掉参数值,只指定方法签名:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let row = self.sections[indexPath.section].rows[indexPath.row] switch row { case .Email: cell.infoLabel.setTitle(cellInfo.email, for: .normal) // 这里只指定方法,不带参数值 cell.infoLabel.addTarget(self, action: #selector(emailPressed(_:)), for: .touchUpInside) cell.imageType.image = UIImage(named: "Email") } return cell }
然后修改@objc方法,通过sender参数拿到按钮的title:
@objc func emailPressed(_ sender: UIButton) { guard let recipient = sender.titleLabel?.text else { return } self.delegate?.dataController(self, recipientEmail: recipient) }
注意:这个方案的前提是按钮的title不会被其他逻辑修改,否则可能拿到错误的值。
方案二:自定义TableViewCell(最规范)
如果你的Cell逻辑比较复杂,或者不想依赖按钮title,自定义Cell是更稳妥的方式:
首先创建自定义Cell类,添加一个存储邮箱的属性和点击回调闭包:
class EmailTableViewCell: UITableViewCell { // 假设你的按钮和图片控件已经在Cell里定义好 @IBOutlet weak var infoLabel: UIButton! @IBOutlet weak var imageType: UIImageView! var email: String? var emailTappedHandler: ((String) -> Void)? override func awakeFromNib() { super.awakeFromNib() // 给按钮添加点击事件 infoLabel.addTarget(self, action: #selector(onEmailButtonTapped), for: .touchUpInside) } @objc private func onEmailButtonTapped() { guard let email = email else { return } emailTappedHandler?(email) } }
然后在cellForRowAt中配置Cell并设置回调:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let row = self.sections[indexPath.section].rows[indexPath.row] switch row { case .Email: guard let cell = tableView.dequeueReusableCell(withIdentifier: "EmailCell") as? EmailTableViewCell else { return UITableViewCell() } let targetEmail = cellInfo.email! cell.infoLabel.setTitle(targetEmail, for: .normal) cell.email = targetEmail // 设置回调,把邮箱地址传递给代理 cell.emailTappedHandler = { [weak self] recipient in self?.delegate?.dataController(self!, recipientEmail: recipient) } cell.imageType.image = UIImage(named: "Email") return cell default: return UITableViewCell() } }
这种方式把Cell的逻辑封装在自己的类里,代码更清晰,也避免了耦合。
方案三:给UIButton添加关联对象(灵活)
如果你不想自定义Cell,还可以通过Objective-C的关联对象给UIButton动态添加一个存储邮箱的属性:
首先定义关联对象的key和扩展:
// 定义唯一的关联对象key private var RecipientEmailKey: UInt8 = 0 extension UIButton { // 给UIButton添加一个存储邮箱的属性 var recipientEmail: String? { get { return objc_getAssociatedObject(self, &RecipientEmailKey) as? String } set { objc_setAssociatedObject(self, &RecipientEmailKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } }
然后在cellForRowAt中给按钮设置这个属性:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let row = self.sections[indexPath.section].rows[indexPath.row] switch row { case .Email: cell.infoLabel.setTitle(cellInfo.email, for: .normal) // 给按钮绑定邮箱地址 cell.infoLabel.recipientEmail = cellInfo.email! cell.infoLabel.addTarget(self, action: #selector(emailPressed(_:)), for: .touchUpInside) cell.imageType.image = UIImage(named: "Email") } return cell }
最后在@objc方法中取出这个属性:
@objc func emailPressed(_ sender: UIButton) { guard let recipient = sender.recipientEmail else { return } self.delegate?.dataController(self, recipientEmail: recipient) }
另外提醒一下,你的代理方法有个拼写错误:funcdataController应该改成func dataController,否则会编译报错。
内容的提问来源于stack exchange,提问作者user3628240
相关产品推荐
相关产品推荐

