Swift中UITableView动态数据搜索功能失效问题求助
我帮你排查出了几个导致搜索过滤功能失效的核心问题,咱们一步步来修复:
1. UISearchBar代理方法签名错误且被私有化
你当前的代理方法用了旧版Swift语法,还加了private修饰符,这会导致系统无法正确调用这些方法。请把所有搜索相关的代理方法改成Swift 3+的标准写法,并且去掉private:
// 替换你原来的private代理方法 func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { isSearching = true } func searchBarTextDidEndEditing(_ searchBar: UISearchBar) { isSearching = false } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { isSearching = false searchBar.text = "" // 清空搜索框 menuTableView.reloadData() // 刷新表格回到原始数据 } func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { isSearching = false searchBar.resignFirstResponder() // 收起键盘 } func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { // 搜索逻辑我们后面再调整 }
2. 数据存储逻辑混乱,dishNameArray初始化时机错误
你现在是在cellForRowAt方法里往dishNameArray添加数据,这会导致重复添加,而且只有当cell被复用时才会有数据,完全不符合逻辑。正确的做法是:在你从服务端拿到ResMenuService.instance.categoryModelInstance之后,一次性把所有分类名存入数组,比如在数据加载完成的回调里添加:
// 假设你在获取服务端数据成功后调用这个方法 func setupDishData() { dishNameArray = ResMenuService.instance.categoryModelInstance.map { $0.categoryName } }
3. cellForRowAt里的逻辑覆盖了搜索结果
当isSearching为true时,你先设置了搜索结果的文本,但后面又直接用原始模型覆盖了这个值,导致永远显示原始数据。更合理的是直接过滤整个模型数组,而不是只存名字,这样cell可以直接使用模型的完整数据:
首先把filteredData改成模型数组类型(替换原来的var filteredData = [String]()):
// 这里的CategoryModel是你对应ResMenuService中categoryModelInstance的模型类名 var filteredCategoryModels = [CategoryModel]()
然后修改搜索方法的逻辑:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { guard let searchText = searchBar.text, !searchText.isEmpty else { filteredCategoryModels.removeAll() isSearching = false menuTableView.reloadData() return } // 根据分类名过滤模型数组 filteredCategoryModels = ResMenuService.instance.categoryModelInstance.filter { $0.categoryName.lowercased().contains(searchText.lowercased()) } isSearching = !filteredCategoryModels.isEmpty menuTableView.reloadData() }
接着调整numberOfRowsInSection的逻辑:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if tableView == menuTableView{ if isSearching{ return filteredCategoryModels.count } return ResMenuService.instance.categoryModelInstance.count } else{ return AllReviewsService.instance.allReviewsModel.count } }
最后修复cellForRowAt的逻辑,确保搜索状态下使用过滤后的模型:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if tableView == menuTableView{ let cell = menuTableView.dequeueReusableCell(withIdentifier: "menuCell", for: indexPath) as! RestaurantMenuTableViewCell // 选择当前要使用的模型 let currentModel: CategoryModel if isSearching { currentModel = filteredCategoryModels[indexPath.row] } else { currentModel = ResMenuService.instance.categoryModelInstance[indexPath.row] } // 设置cell数据 cell.dishTitleLbl.text = currentModel.categoryName cell.cardView.layer.cornerRadius = 5 cell.selectionStyle = .none return cell } else { // 评论cell的逻辑保持不变 let cell = reviewTableView.dequeueReusableCell(withIdentifier: "reviewCell", for: indexPath) as! AllReviewsTableViewCell cell.nameLbl.text = AllReviewsService.instance.allReviewsModel[indexPath.row].name cell.descriptionLbl.text = AllReviewsService.instance.allReviewsModel[indexPath.row].description cell.timeLbl.text = AllReviewsService.instance.allReviewsModel[indexPath.row].time cell.ratingView.rating = Double(AllReviewsService.instance.allReviewsModel[indexPath.row].rating) cell.backgroundColor = UIColor.clear cell.selectionStyle = .none return cell } }
4. 额外优化:确保搜索栏显示取消按钮
在viewDidLoad里添加一行代码,让搜索栏显示取消按钮,方便用户退出搜索状态:
searchBar.showsCancelButton = true
5. 修复点击事件的模型获取逻辑
在tableView(_:didSelectRowAt:)方法里,也要对应调整搜索状态下的模型获取逻辑,确保点击搜索结果时能拿到正确的模型数据:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if tableView == menuTableView{ let selectedModel: CategoryModel if isSearching { selectedModel = filteredCategoryModels[indexPath.row] } else { selectedModel = ResMenuService.instance.categoryModelInstance[indexPath.row] } // 后续使用selectedModel来获取数据,比如minimumSpending等 let minimumSpending = String(ResMenuService.instance.restaurntDetailModelInstance[indexPath.row].minimumSpending) UserDefaults.standard.set(minimumSpending, forKey: "minimumSpending") UserDefaults.standard.synchronize() let categoryModel = ResMenuService.instance.categoryModelInstance let subCategoryModel = selectedModel.subCategories let AddonCategoryModel = subCategoryModel[0].items[0].addonCategory let storyboard = UIStoryboard(name: "Main", bundle: nil) let vc = storyboard.instantiateViewController(withIdentifier: "RestaurantMenuDetailVC") as! RestaurantMenuDetailVC vc.categoryModel = categoryModel vc.subCategoryModel = subCategoryModel vc.AddonCategoryModel = AddonCategoryModel self.navigationController?.pushViewController(vc, animated: true) } else{ print("Hello") } }
做完这些修改后,你的搜索过滤功能应该就能正常工作了。
内容的提问来源于stack exchange,提问作者raheem

