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

Swift 4中点击TableView单元格内RadioButton获取单元格索引的方法

解决TableView中RadioButton点击获取单元格索引的崩溃问题

我来帮你搞定这个问题!你遇到的libc++abi.dylib: terminating with uncaught exception of type NSException崩溃,主要是因为ViewController里给RadioButton绑定target时用了错误的action,另外还有些地方可以优化,让获取单元格索引更可靠。

问题根源分析

  1. 错误的Target Action绑定:在cellForRowAt方法里,你给btnRadioEvet加target时,action参数写得完全不对:
    cell.btnRadioEvet.addTarget(self, action: #selector(getter: cell.btnRadioEvet), for: UIControlEvents.touchUpInside)
    
    btnRadioEvet是UIButton实例,不是方法,这直接触发了崩溃。而且你已经在Cell类里通过IBAction绑定了点击事件,重复加target只会引发冲突。
  2. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:13:00