ios - 使用 NSFetchedResultsController 搜索每个字符 CoreData 的速度非常慢,有大量记录

标签 ios search core-data

我有一个包含 20000 条记录的预加载数据库。

基本上有两个实体在其中完成搜索,City Entity 和另一个是street Entity。 City有“Name”属性,Street Entity也有name属性,city和street都是一对多关系。因为一个城市可以有很多街道。

现在,当用户可以使用任何字符(如“a 或 b”)进行搜索时,它应该向用户显示相应的城市和/或街道。每次我都必须重新加载和重新配置 NSFetchedResultsController。

我已经实现了一个 NSPredicate 来过滤记录。

let predicate = NSPredicate(format:"(name CONTAINS[c] %@) OR (SELF.streets.name CONTAINS[c] %@)",text,text)
 predicateArray.append(predicate)

这个谓词用于过滤记录。我还在使用 MagicalRecord 对 coreData 的包装。搜索过去非常频繁,因为我正在搜索每个字符。

如有任何帮助,我们将不胜感激。

最佳答案

我尝试在内存中过滤 20000 行。速度 super 快!一点都不滞后。看来您将多次访问持久存储,这就是我的建议:

  • 停止使用NSFetchedResultController(在这样做之前尝试第三点它可以工作)
  • 创建两个 NSFetchRequest:其中一个将为您提供城市,另一个将为您提供街道。所以你会得到一系列的城市和一系列的街道。 这种方法将帮助您避免获取效率非常低的关系city.streets。如果您可以将两者组合并映射到单个字符串数组,那就更好了。
  • 非常重要:设置request.returnsObjectsAsFaults = false。否则,您将继续前往数据库获取 city.name 或 street.name。

当搜索文本字段更改时:

  • 首先过滤城市,然后过滤街道。
  • 重新加载tableView

编辑:测试示例 我测试了下面的代码

  • iPhone 6:第一个字符在 100 毫秒到 170 毫秒之间。然后它变得更快。 (2x) 我没有感觉到任何延迟。

  • iPad mini 2:第一个字符在 300 毫秒到 350 毫秒之间。然后它变得更快。 (2x) 有一些滞后。

    class ViewController: UIViewController, UISearchBarDelegate, UITableViewDataSource{
    
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var searchBar: UISearchBar!
    
    var streets = [Street]()
    var cities = [City]()
    
    var filteredStreets: [Street] = []
    var filteredCities: [City] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        cities = findAllCities()
        streets = findAllStreets()
        filteredCities = cities
        filteredStreets = streets
    }
    
    func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
        filterItemsWithCurrentSearchText(searchText)
    }
    
    func filterItemsWithCurrentSearchText(text: String){
        if text.isEmpty {
            filteredStreets = streets
            filteredCities = cities
        } else {
            NSLog("1")
            filteredStreets = streets.filter{ $0.name.rangeOfString(text, options: .CaseInsensitiveSearch) != nil }
            NSLog("2")
            filteredCities = cities.filter{ $0.name.rangeOfString(text, options: .CaseInsensitiveSearch) != nil }
            NSLog("3")
        }
        tableView.reloadData()
        NSLog("4")
    }
    
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return filteredStreets.count + filteredCities.count
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell")!
    
        if indexPath.row < filteredCities.count{
            cell.textLabel!.text = "City:" + filteredCities[indexPath.row].name
        }else{
            cell.textLabel!.text = "Street:" + filteredStreets[indexPath.row-filteredCities.count].name
        }
        return cell
    }
    
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    
    func findAllCities() -> [City]{
        let request = City.MR_createFetchRequest()
        request.returnsObjectsAsFaults = false
        return City.MR_executeFetchRequest(request) as! [City]
    }
    
    func findAllStreets() -> [Street]{
        let request = Street.MR_createFetchRequest()
        request.returnsObjectsAsFaults = false
        return Street.MR_executeFetchRequest(request) as! [Street]
    }
    }
    

关于ios - 使用 NSFetchedResultsController 搜索每个字符 CoreData 的速度非常慢,有大量记录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40418506/

相关文章:

ios - 在 swift 中单击 UILabel 时出现空白屏幕

ios - 在 uitableview 单元格中快速显示你好

iOS - 安排 UIAlertController 在 View 转换完成后显示

java - 哪种数据结构更适合使用顺序搜索来搜索元素 - 数组列表还是链接列表?

linux - 使用 "sed"在 Redhat Linux 上查找和替换

android - 我如何使用 baseadapter 过滤 ListView

ios - 创建UIManagedDocument和初始iCloud同步

ios - 如果我在应用商店版本上升级测试版本,iCloud 不会获取以前版本的数据

ios - CoreData 谓词 : string property length?

ios - 以编程方式阻止 iOS 应用程序中的来电显示