UISearchController问题:筛选后选中项索引与原始数组不匹配
问题分析与解决方案
嘿,这个问题我太熟啦!你遇到的核心问题是筛选状态下的索引不匹配——当你在搜索筛选后点击行时,你用的是筛选后数组的索引去操作原始数组,这就导致修改错了元素。
问题根源
看你的didSelectRowAt方法:
let accessoryType: UITableViewCell.AccessoryType = manager.changeState(at: indexPath.row) ? .checkmark : .none
当isFiltering为true时,indexPath.row对应的是filteredTasks里的位置,而不是manager.tasks(原始数组)的真实位置。比如你筛选后第三个元素是原始数组的第五个,你点击后却修改了原始数组的第三个元素,取消搜索自然就看到错误的结果啦。
修复方案
我们需要先拿到筛选后点击的Task对象,再找到它在原始数组里的真实索引,然后再去修改状态。具体修改你的didSelectRowAt方法:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) // 确定要修改的原始数组索引 let targetIndex: Int if isFiltering { // 先获取筛选后的当前任务 guard let currentTask = filteredTasks?[indexPath.row] else { return } // 找到它在原始数组中的真实位置 // 这里假设你的Task实现了Equatable协议,如果没有,用唯一ID匹配 guard let index = manager.tasks.firstIndex(where: { $0 == currentTask }) else { return } targetIndex = index } else { // 非筛选状态直接用当前索引 targetIndex = indexPath.row } // 修改状态并更新cell let accessoryType: UITableViewCell.AccessoryType = manager.changeState(at: targetIndex) ? .checkmark : .none tableView.cellForRow(at: indexPath)?.accessoryType = accessoryType }
额外说明
如果你的Task类没有实现Equatable协议,记得用唯一标识来匹配(比如每个任务的taskId),替换上面的匹配逻辑:
guard let index = manager.tasks.firstIndex(where: { $0.taskId == currentTask.taskId }) else { return }
这样就能确保精准找到原始数组中对应的任务,不会再出现索引错位的问题啦!
内容的提问来源于stack exchange,提问作者SilentKunZ
相关产品推荐
相关产品推荐

