通过 fetchedResultsController 在 Core Data 中使用大型基础
Working with big base in Core Data via fetchedResultsController
也许有人有使用大型核心数据库的经验(我的数据库中有 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 添加字符时我仍然有一些 "lags")
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!)
}
这里有一些指南:
- 使用批处理。将您的提取请求的
fetchBatchSize
设置为 50
,并将 returnsObjectsAsFaults
设置为 NO
。
- 在您的 table 视图中使用估计的高度。
estimatedRowHeight
或 -tableView:estimatedHeightForRowAtIndexPath:
或 UITableViewDelegate
都可以。
这将防止在每次重新加载时将所有 32K 记录加载到内存中。
不是因为你有 32k 条记录。那并不大。问题是您显然是在尝试使用字符串属性对这些记录进行排序:
let sortDescriptor = NSSortDescriptor(key: "cardName", ascending: true)
按字符串值对 32k 条记录进行排序是一项繁重的工作。这需要时间。有几种加速它的可能性:
- 如果可能,按数字或日期属性而不是字符串排序。这 快 多了。如果您的数据没有有用的数字属性,也许您可以编一个可以得到相同排序结果的属性。
- 通过选中模型编辑器中的 "indexed" 框,告诉 Core Data 索引该属性。这会有所帮助,但不如对数字属性进行排序那么有用。
也许有人有使用大型核心数据库的经验(我的数据库中有 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 添加字符时我仍然有一些 "lags")
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!)
}
这里有一些指南:
- 使用批处理。将您的提取请求的
fetchBatchSize
设置为50
,并将returnsObjectsAsFaults
设置为NO
。 - 在您的 table 视图中使用估计的高度。
estimatedRowHeight
或-tableView:estimatedHeightForRowAtIndexPath:
或UITableViewDelegate
都可以。
这将防止在每次重新加载时将所有 32K 记录加载到内存中。
不是因为你有 32k 条记录。那并不大。问题是您显然是在尝试使用字符串属性对这些记录进行排序:
let sortDescriptor = NSSortDescriptor(key: "cardName", ascending: true)
按字符串值对 32k 条记录进行排序是一项繁重的工作。这需要时间。有几种加速它的可能性:
- 如果可能,按数字或日期属性而不是字符串排序。这 快 多了。如果您的数据没有有用的数字属性,也许您可以编一个可以得到相同排序结果的属性。
- 通过选中模型编辑器中的 "indexed" 框,告诉 Core Data 索引该属性。这会有所帮助,但不如对数字属性进行排序那么有用。