对Table View应用筛选后如何保留原始的indexPath.row值?
核心问题原因
你当前只维护了单个数组作为数据源,触发筛选操作时该数组会被替换为筛选后的结果,此时通过indexPath.row获取到的是筛选后数组的下标,自然无法对应原始数据库的下标。
具体修改步骤
第一步:在当前ViewController中声明两类数据源
分别存储全量原始数据、筛选后用于列表展示的数据,筛选操作永远不修改原始数据源:// 全量原始数据源,仅首次拉取数据时赋值,后续不修改 var originalMealPlans: [MealPlan] = [] // 筛选后展示用数据源,筛选操作仅修改该数组 var filteredMealPlans: [MealPlan] = []首次拉取到数据后,给两个数组赋初始值:
originalMealPlans = 从数据库拉取的全量原始数据 // 初始无筛选,展示数组等于原始数组 filteredMealPlans = originalMealPlans第二步:给数据模型绑定原始下标(可选,推荐)
如果你不想后续每次查询原始下标损耗性能,可以给MealPlan模型新增originIndex属性,首次拉取数据时就绑定好原始下标:for (index, meal) in 从数据库拉取的全量原始数据.enumerated() { var tempMeal = meal tempMeal.originIndex = index originalMealPlans.append(tempMeal) }不想修改模型的话,也可以让
MealPlan实现Equatable协议,后续通过originalMealPlans.firstIndex(of: 选中的对象)获取原始下标。第三步:修改TableView代理方法,全部使用筛选后数组作为数据源
调整numberOfRowsInSection:func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return filteredMealPlans.count }调整
cellForRowAt:func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "MealPlanCell", for: indexPath) as! MealPlanCell let mealPlanInTable = filteredMealPlans[indexPath.row] cell.displayMealPlan(mealPlanInTable) return cell }第四步:修改传参逻辑,传递原始下标而非当前列表的下标
调整prepare方法:override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let indexPath = tableView.indexPathForSelectedRow else { return } // 从筛选数组取选中的对象 let selectedMeal = filteredMealPlans[indexPath.row] let NextVC = segue.destination as! NextViewController // 传递绑定的原始下标 NextVC.currentMealPlanIndex = selectedMeal.originIndex // 没改模型的话用这行替代: // NextVC.currentMealPlanIndex = originalMealPlans.firstIndex(of: selectedMeal) ?? 0 }第五步:调整筛选逻辑
筛选按钮触发查询后,仅更新filteredMealPlans数组,之后调用tableView.reloadData()刷新列表即可,不要修改originalMealPlans的内容。
额外说明
如果你的数据量较大、存在重复数据,优先选择给模型新增原始下标的方案,避免firstIndex查询出现性能问题、下标匹配错误的情况。
内容的提问来源于stack exchange,提问作者amirbt17
相关产品推荐
相关产品推荐

