iOS UITableView搜索数据时选择行出现多选问题的解决方案问询
问题根因
- 你存储选中状态的
selectedIndex是对应当前数据源的行索引,搜索切换为过滤后的searchedText数据源后,原selectedIndex和新数据源的行索引不匹配,导致取消旧选中行时找错/找不到目标行 - cellForRow中同时存在两种选中判断逻辑(行索引匹配、选中名称匹配),逻辑冲突导致UI展示异常
- 直接操作cell修改选中图标,没有通过数据源驱动UI刷新,cell复用或列表reload后状态会错乱
修复方案
- 统一选中判断逻辑:直接用选中的员工id作为唯一判断标准,不要依赖行索引,避免数据源切换后索引失效的问题
- 每次选中新行后刷新列表,所有cell的选中状态基于数据源自动更新,避免直接操作cell的UI
- 移除cellForRow中重复的选中状态判断逻辑,简化代码逻辑
修复后的代码实现
extension EmpTableView: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if searching { return searchedText.count } else { return makeList?.count ?? 0 } } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "CustomoCell", for: indexPath) as! CustomCell let row = indexPath.row // 统一获取当前行的员工模型 let currentEmp: EmpModel? // 替换为你实际的员工模型类名 if searching { currentEmp = searchedText[row] }else { currentEmp = makeList?[row] } cell.lblTitle.text = currentEmp?.emp_name ?? "" // 统一选中状态判断:匹配选中的员工id let selectedId = constants.config.selectedArray.count >= 2 ? constants.config.selectedArray[1] : "" if currentEmp?.emp_id == selectedId { cell.imageSelection.image = #imageLiteral(resourceName: "Selected") } else { cell.imageSelection.image = #imageLiteral(resourceName: "Unselected") } return cell } } extension EmpTableView: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let row = indexPath.row // 获取当前点击的员工模型 let currentEmp: EmpModel? if searching { currentEmp = searchedText[row] } else { currentEmp = makeList?[row] } guard let emp = currentEmp else { return } // 取出当前已选中的id let selectedId = constants.config.selectedArray.count >= 2 ? constants.config.selectedArray[1] : "" constants.config.selectedArray.removeAll() if emp.emp_id == selectedId { // 重复点击选中行,取消选中 selectedIndex = -1 } else { // 选中新行 constants.config.selectedArray.append(emp.emp_name ?? "") constants.config.selectedArray.append(emp.emp_id ?? "") selectedIndex = row } // 刷新列表,所有cell的选中状态会自动根据数据源刷新 tableView.reloadData() self.searchBar.searchTextField.endEditing(true) } } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { if searchText.isEmpty { searching = false searchedText.removeAll() } else { searching = true searchedText = makeList.filter{$0.emp_name?.range(of: searchText, options: .caseInsensitive) != nil} } empTable.reloadData() } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.text = "" }
优化说明
- 用员工唯一id作为选中状态的判断依据,不受搜索过滤后数据源变化的影响,全量列表和搜索结果列表都能正确识别选中状态
- 所有UI展示完全由数据源驱动,避免cell复用导致的状态错乱
- 移除了重复冲突的逻辑,代码可维护性更高
内容的提问来源于stack exchange,提问作者Rakshit Kumar
相关产品推荐
相关产品推荐

