【问题标题】:Working with big base in Core Data via fetchedResultsController通过 fetchedResultsController 在 Core Data 中使用大基础
【发布时间】:2016-11-15 01:13:04
【问题描述】:

也许有人有使用大型核心数据库的经验(我的数据库中有 32k 行,我需要向用户展示所有这些数据库并在其中进行一些搜索)以及何时尝试阅读我的 fetchedResultsController 的基础我有 3-5 秒的延迟,我该如何解决这个问题? 我可以在一些后台线程中阅读这个基础吗? 或者如果我通过关系在某些部分上分开我的基础是否有帮助? 我尝试在 viewDidAppear 中加载我的基地

    override func viewDidAppear(_ animated: Bool) {
        DispatchQueue.main.async {
            self.connectFetchedRequest()
            self.tableView.reloadData()
            self.indicatorLoad.stopAnimating()
        }
    }

    func connectFetchedRequest() {
        do {
            try self.fetchedResultsController.performFetch()
        }catch {
            print(error)
        }
    }

我使用 UISearchBarDelegate 方法在基础中进行搜索(但在向 searchText 添加字符时我仍然有一些“滞后”)

    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
        block?.cancel()
        block = DispatchWorkItem {
            let predicate = NSPredicate(format: "cardName contains[c] %@", searchText)
            self.fetchedResultsController.fetchRequest.predicate = predicate
            self.connectFetchedRequest()
            DispatchQueue.main.async(execute: {
                self.tableView.reloadData()
            })
        }
        DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 0.5, execute: block!)
    }

我使用以下代码创建了 fetchedResultsController

    lazy var context: NSManagedObjectContext = {
        let appDelegate = (UIApplication.shared.delegate as? AppDelegate)
        return appDelegate!.managedObjectContext
    }()

    lazy var fetchedResultsController: NSFetchedResultsController<CardsBaseClass> = {
        let fetchRequest = NSFetchRequest<CardsBaseClass>(entityName: "CardsBase")
        let sortDescriptor = NSSortDescriptor(key: "cardName", ascending: true)
        fetchRequest.sortDescriptors = [sortDescriptor]

        fetchRequest.fetchBatchSize = 50
        fetchRequest.returnsObjectsAsFaults = false

        let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.context, sectionNameKeyPath: nil, cacheName: nil)
        fetchedResultsController.delegate = self
        return fetchedResultsController
    }()

为了添加来自其他 viewController 的新谓词(我打开 .overFullScreen,所以我的带有 base 的主视图也打开了)我使用以下代码

predicateArrayClass.addPredicate(predicate: predicateType)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "updateTableViewByNewPredicate"), object: nil, userInfo: nil)
self.dismiss(animated: true, completion: nil)

我在哪里调用了更新 fetchResultController 函数

func updateTableViewByNewPredicate() {
        searchController.searchBar.text! = ""
        let predicateArray = predicateArrayClass.arrayOfPredicates
        block = DispatchWorkItem {
            self.fetchedResultsController.fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicateArray)
            self.connectFetchedRequest()
            DispatchQueue.main.async(execute: {
                self.tableView.reloadData()
            })
        }
        DispatchQueue.global(qos: .background).async(execute: block!)
}

【问题讨论】:

  • 您可以编辑您的问题以在您创建提取结果控制器的位置添加代码吗?你如何配置它可能是一个关键的细节。
  • 已添加,并且我使用 NSFetcherResultControllerDelegate 方法更新 tableView 数据(controllerWillChangeContent、controllerDidChangeContent 和 didChangeObject)。我通过“茶壶”在答案中添加了代码,但加载时间仍然是几秒钟

标签: swift sqlite core-data nsfetchedresultscontroller uisearchbardelegate


【解决方案1】:

以下是一些指导方针:

  1. 使用批处理。将 fetch 请求的 fetchBatchSize 设置为 50,将 returnsObjectsAsFaults 设置为 NO。
  2. 在表格视图中使用估计高度。 estimatedRowHeight 或 -tableView:estimatedHeightForRowAtIndexPath: 或 UITableViewDelegate 都可以。

这将防止在每次重新加载时加载内存中的所有 32K 记录。

【讨论】:

  • 谢谢,现在使用 base 更好了,但是当 base 连接时仍然有一些加载时间,是真的要解决这个问题还是需要在 fetchedResultsController 中连接 base 的时间?
  • @Skie 你可以通过执行后台获取请求并将 NSManagedObjectIDs 传递给主线程来预热 NSPersistentStoreCoordinator 的缓存,可能在应用程序启动之后。
【解决方案2】:

这不是因为您有 32k 条记录。那不是很大。问题是您显然是在尝试使用字符串属性对这些记录进行排序:

let sortDescriptor = NSSortDescriptor(key: "cardName", ascending: true)

按字符串值对 32k 条记录进行排序是一项繁重的工作。这需要时间。加快速度有两种可能性:

  1. 如果可能,请按数字或日期属性而非字符串排序。这快得多。如果您的数据没有有用的数字属性,也许您可​​以制作一个可以提供相同排序结果的数据。
  2. 通过选中模型编辑器中的“索引”框,告诉 Core Data 索引该属性。这会有所帮助,但不如按数字属性排序。

【讨论】:

  • 谢谢,我为我的“cardName”添加了“indexed”,现在所有的基础都被快速排序了。我有一个新问题。我从其他视图控制器更新了一些用于在此基础中过滤的谓词,第一个过滤器加载大约 10 秒,但是当我使用这个和/或新的谓词过滤器时,我只有 1 秒的延迟来重新加载搜索结果。为什么会发生这种情况?也许我在内存中调用了新的基础(我试图捕捉这个但我没有调用任何新的 NSFetchRequestControllers)或者它不是更新 fetchedResultsController 的好方法?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-05
  • 1970-01-01
  • 1970-01-01
  • 2012-05-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多