You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

查询数组过大耗时,如何让UISearchBar展示完整输入文本的搜索结果

问题根因

你的代码存在两个核心问题导致旧搜索结果覆盖新结果:

  • 你写的校验逻辑searchText == searchTextBeingQuireid完全无效:这两个值是你在同一个闭包作用域里赋值的相同值,判断永远为真,无法过滤掉已经过时的旧搜索任务
  • 连续输入时会生成多个并发的后台搜索任务,耗时更长的旧任务(比如首字母搜索)结束后依然会执行UI刷新,覆盖新搜索的结果
修复方案

推荐使用可取消的DispatchWorkItem管理搜索任务,从根源上避免旧任务干扰,还可以搭配防抖逻辑提升性能:

  1. 首先给当前控制器新增属性,存储当前活跃的搜索任务:
private var currentSearchWorkItem: DispatchWorkItem?
  1. 替换searchBar的textDidChange实现:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    // 取消所有旧的未完成搜索任务
    currentSearchWorkItem?.cancel()
    
    let workItem = DispatchWorkItem { [weak self] in
        guard let self = self, !workItem.isCancelled else { return }
        
        var searchedRecords = [AlimentObject]()
        let words = Set(searchText.split(separator: " ").map(String.init))
        
        if searchText.isEmpty {
            searchedRecords = []
        } else {
            // 前缀匹配结果
            var classicFilter = baseOuChercheAliments.filter {
                $0.nomAliment.range(of: searchText, options: .anchored) != nil
            }
            classicFilter.sort { $0.nomAliment < $1.nomAliment }
            
            // 全词包含匹配结果
            var complexFilter = baseOuChercheAliments.filter { object in
                guard !workItem.isCancelled else { return false }
                return words.allSatisfy { word in
                    object.nomAliment.localizedCaseInsensitiveContains(word)
                }
            }
            complexFilter.sort { $0.nomAliment < $1.nomAliment }
            
            // 结果去重合并
            let subtraction = Array(Set(complexFilter).subtracting(classicFilter))
                .sorted { $0.nomAliment > $1.nomAliment }
            searchedRecords = classicFilter + subtraction
        }
        
        // 仅未取消的最新任务可以刷新UI
        guard !workItem.isCancelled else { return }
        DispatchQueue.main.async {
            self.baseDeDonneesAlimentsFiltree = searchedRecords
            self.tableView.reloadData()
        }
    }
    
    currentSearchWorkItem = workItem
    // 可选:加300ms防抖,用户停止输入后再执行搜索,减少无效计算,不需要可直接去掉延迟参数
    DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + 0.3, execute: workItem)
}
轻量化替代方案

如果你不需要取消旧任务,只想用最低成本修复,也可以通过全局最新搜索关键词校验实现:

  1. 新增控制器属性:
private var latestSearchKeyword: String = ""
  1. 修改搜索逻辑:
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    // 先更新最新搜索关键词
    latestSearchKeyword = searchText
    
    DispatchQueue.global(qos: .default).async { [self] in
        // 原有搜索逻辑不变...
        
        // 刷新UI前校验当前搜索是否是最新的
        guard searchText == latestSearchKeyword else { return }
        DispatchQueue.main.async {
            baseDeDonneesAlimentsFiltree = searchedRecords
            self.tableView.reloadData()
        }
    }
}

内容的提问来源于stack exchange,提问作者Maria23

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 18:06:03