Swift 4中点击TableView单元格内RadioButton获取单元格索引的方法
我来帮你搞定这个问题!你遇到的libc++abi.dylib: terminating with uncaught exception of type NSException崩溃,主要是因为ViewController里给RadioButton绑定target时用了错误的action,另外还有些地方可以优化,让获取单元格索引更可靠。
问题根源分析
- 错误的Target Action绑定:在
cellForRowAt方法里,你给btnRadioEvet加target时,action参数写得完全不对:cell.btnRadioEvet.addTarget(self, action: #selector(getter: cell.btnRadioEvet), for: UIControlEvents.touchUpInside)btnRadioEvet是UIButton实例,不是方法,这直接触发了崩溃。而且你已经在Cell类里通过IBAction绑定了点击事件,重复加target只会引发冲突。 - Tag复用的潜在风险:用
sender.tag传递indexPath.row虽然简单,但TableView的Cell是复用的,某些场景下会出现tag混乱,不是最稳妥的方式。
解决方案
步骤1:移除错误的重复Target绑定
先把ViewController的cellForRowAt里这行错误代码删掉:
cell.btnRadioEvet.addTarget(self, action: #selector(getter: cell.btnRadioEvet), for: UIControlEvents.touchUpInside)
步骤2:修改Cell类,通过层级查找获取IndexPath
在TVCIsGuvenligi类里,修改按钮的IBAction方法,用递归查找的方式获取当前Cell所在的TableView,进而拿到IndexPath,这种方式比tag靠谱得多:
import UIKit class TVCIsGuvenligi: UITableViewCell { lazy var radioButtonGroup: [RadioButton] = { return [ btnRadioEvet, btnRadioHayir, ] }() @IBOutlet var lblSoru: UILabel! @IBOutlet var lblSoruAyrinti: UILabel! @IBOutlet var lblEvet: UILabel! @IBOutlet var lblHayir: UILabel! @IBOutlet var btnRadioEvet: RadioButton! @IBOutlet var btnRadioHayir: RadioButton! @IBAction func btnRadioEvet(_ sender: RadioButton) { updateRadioButton(sender) // 获取当前单元格的IndexPath guard let indexPath = getCurrentIndexPath() else { return } print("index \(indexPath)") } @IBAction func btnRadioHayir(_ sender: RadioButton) { updateRadioButton(sender) // 获取当前单元格的IndexPath guard let indexPath = getCurrentIndexPath() else { return } print("index \(indexPath)") } override func awakeFromNib() { super.awakeFromNib() } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) } func updateRadioButton(_ sender: RadioButton){ radioButtonGroup.forEach { $0.isSelected = false } sender.isSelected = !sender.isSelected } // 递归查找当前Cell所在的TableView,并返回IndexPath private func getCurrentIndexPath() -> IndexPath? { var currentView: UIView? = self while currentView != nil { if let tableView = currentView as? UITableView { return tableView.indexPath(for: self) } currentView = currentView?.superview } return nil } }
步骤3:处理Cell复用的状态混乱问题
因为TableView的Cell会被复用,滚动时可能出现RadioButton状态错乱,所以要在ViewController的cellForRowAt里重置状态(如果有保存的选中状态,还要记得恢复):
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cellIs", for: indexPath) as! TVCIsGuvenligi cell.lblSoru.text = myTitle[indexPath.row] cell.lblSoruAyrinti.text = myTitle[indexPath.row] // 重置RadioButton状态,避免复用导致的错误 cell.radioButtonGroup.forEach { $0.isSelected = false } // 如果有保存的选中状态,在这里恢复(示例) // 假设你有一个数组selectedButtonStates,存储每行选中的按钮标识 // if let selectedButton = selectedButtonStates[indexPath.row] { // if selectedButton == "evet" { // cell.btnRadioEvet.isSelected = true // } else { // cell.btnRadioHayir.isSelected = true // } // } return cell }
总结
这样修改后,既解决了崩溃问题,又能稳定获取点击RadioButton所在的单元格IndexPath,还避开了tag复用带来的潜在坑。
内容的提问来源于stack exchange,提问作者Meltem Akpolat
相关产品推荐
相关产品推荐

