如何在UITableView中基于Model数组实现搜索功能?
解决UISearchBar配合可展开UITableViewCell的搜索与Cell配置崩溃问题
一、梳理数据源与状态管理
先明确核心变量,区分原始数据、搜索结果及展开状态,避免数据混淆:
// 原始全量数据源 var originalData: [YourCurrencyModel] = [] // 搜索结果缓存数组 var searchResults: [YourCurrencyModel] = [] // 标记是否处于搜索模式 var isSearching = false // 存储已展开的行索引(单组列表场景) var expandedIndexPaths = Set<IndexPath>()
二、实现UISearchBar的搜索过滤逻辑
通过UISearchBarDelegate方法完成数据过滤,切换搜索状态并刷新表格:
extension YourViewController: UISearchBarDelegate { func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { guard !searchText.trimmingCharacters(in: .whitespaces).isEmpty else { // 搜索框为空时恢复原始数据,退出搜索模式 isSearching = false tableView.reloadData() return } // 根据Model字段过滤数据(示例匹配货币全称,按需替换为你的字段) searchResults = originalData.filter { model in model.currencyNormalFullName.lowercased().contains(searchText.lowercased()) } isSearching = true tableView.reloadData() } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.text = "" isSearching = false searchResults.removeAll() tableView.reloadData() searchBar.resignFirstResponder() } }
三、修复Cell配置崩溃问题
直接访问Cell的UI属性崩溃,本质是Cell复用逻辑不严谨或类型转换失败。通过给自定义Cell添加封装的配置方法解决:
1. 给自定义Cell添加配置方法
将UI赋值逻辑封装在Cell内部,避免外部直接操作UI组件:
class ExpandableCurrencyCell: UITableViewCell { @IBOutlet weak var currencyNormalFullLabel: UILabel! @IBOutlet weak var expandedContentLabel: UILabel! // 统一配置Cell的方法,传入数据和展开状态 func configure(with model: YourCurrencyModel, isExpanded: Bool) { // 填充基础数据 currencyNormalFullLabel.text = model.currencyNormalFullName // 根据展开状态控制扩展内容显示 expandedContentLabel.isHidden = !isExpanded if isExpanded { expandedContentLabel.text = model.expandedDetail // 替换为你的扩展内容字段 } } }
2. 在cellForRowAt中正确调用配置
确保Cell类型转换安全,再调用配置方法:
extension YourViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return isSearching ? searchResults.count : originalData.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { guard let cell = tableView.dequeueReusableCell(withIdentifier: "ExpandableCurrencyCell", for: indexPath) as? ExpandableCurrencyCell else { // 转换失败时返回默认Cell,避免崩溃 return UITableViewCell(style: .default, reuseIdentifier: nil) } // 获取当前行对应的数据 let currentModel = isSearching ? searchResults[indexPath.row] : originalData[indexPath.row] // 判断当前行是否处于展开状态 let isExpanded = expandedIndexPaths.contains(indexPath) // 调用Cell的配置方法 cell.configure(with: currentModel, isExpanded: isExpanded) return cell } }
四、处理可展开Cell的状态切换
点击Cell时更新展开状态,注意搜索模式下的索引对应搜索结果数组:
extension YourViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) if expandedIndexPaths.contains(indexPath) { expandedIndexPaths.remove(indexPath) } else { expandedIndexPaths.insert(indexPath) } // 刷新当前行,更新展开状态 tableView.reloadRows(at: [indexPath], with: .automatic) } }
额外注意事项
- 确保Storyboard/XIB中Cell的复用标识符与代码一致;
- 过滤逻辑可按需扩展为多字段匹配(如同时匹配货币代码和全称);
- 若为分组表格,需调整展开状态存储方式(如用
[Int: Bool]标记每组是否展开)。
内容的提问来源于stack exchange,提问作者CT4TuEI3
相关产品推荐
相关产品推荐

