Swift委托函数中获取选中TableView Cell所在Section的方法
解决TableView Cell按钮点击时获取Section的问题
问题根源
你遇到的崩溃本质是:不同分组(Section)里的单元格(Cell)可能有相同的indexPath.row值,只传递row的话,控制器无法区分当前点击的Cell属于哪个Section,导致访问subCategoryModel时取到了错误的索引,进而触发数组越界崩溃。
具体解决方案
我们只需要修改委托逻辑,让它同时传递Section和Row的信息,就能精确定位点击位置。下面是分步修改方案:
1. 更新委托协议
把原来只传row的协议,改成传递完整的IndexPath(它本身就包含section和row,是最灵活的方式):
protocol ResMenuDetailDelegate { func addOnBtnTapped(at indexPath: IndexPath) }
2. 修改Cell的按钮点击逻辑
这里提供两种可靠的方式获取当前Cell的IndexPath:
方式一:直接从TableView获取(推荐)
不需要额外存储数据,通过Cell的父视图找到对应的TableView,再拿到索引:
var delegate: ResMenuDetailDelegate? @IBAction func addBtnTapped(_ sender: Any) { // 找到当前Cell所属的TableView,再获取对应的IndexPath guard let tableView = self.superview as? UITableView, let indexPath = tableView.indexPath(for: self) else { return } delegate?.addOnBtnTapped(at: indexPath) }
方式二:配置Cell时存储IndexPath
在Cell类里新增一个属性,专门存当前Cell的索引:
var delegate: ResMenuDetailDelegate? var indexPath: IndexPath? // 新增存储索引的属性 @IBAction func addBtnTapped(_ sender: Any) { guard let indexPath = indexPath else { return } delegate?.addOnBtnTapped(at: indexPath) }
3. 调整TableView的cellForRow方法
- 如果用方式一:直接删掉
cell.addBtn.tag = indexPath.row这行代码(tag已经没用了)。 - 如果用方式二:在配置Cell时给
indexPath属性赋值:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if tableView == resMenuTableView{ let cell = resMenuTableView.dequeueReusableCell(withIdentifier: "detailMenuCell", for: indexPath) as! RestaurantMenuDetailTVC // 先把当前要展示的item取出来,避免重复写长索引 let currentItem = subCategoryModel![indexPath.section].items[indexPath.row] cell.dishTitleLbl.text = currentItem.itemName cell.descriptionLbl.text = currentItem.itemDescription cell.priceLbl.text = String(currentItem.itemPrice) // 方式一:不需要设置tag,删除这行 // cell.addBtn.tag = indexPath.row // 方式二:给Cell的indexPath属性赋值 // cell.indexPath = indexPath cell.delegate = self cell.selectionStyle = .none cell.backgroundColor = UIColor.clear return cell } // 记得处理其他TableView的情况,返回默认Cell return UITableViewCell() }
4. 更新控制器的委托实现
现在可以通过indexPath精准拿到section和row,再也不会取错数据了:
extension RestaurantMenuDetailVC : ResMenuDetailDelegate{ func addOnBtnTapped(at indexPath: IndexPath) { print("点击了Section: \(indexPath.section), Row: \(indexPath.row)") let currentItem = subCategoryModel![indexPath.section].items[indexPath.row] let addonCategory = currentItem.addonCategory print(addonCategory as Any) // 接下来就可以把addonCategory传给弹窗的TableView了 } }
额外提醒
尽量不要用tag传递多维度的位置信息,因为tag是单一Int值,无法同时存储section和row,不同section的row很容易重复,会埋下崩溃隐患。直接传递IndexPath是iOS开发中定位TableView Cell位置的标准做法。
内容的提问来源于stack exchange,提问作者Awais
相关产品推荐
相关产品推荐

