我有一个具有表格视图的应用程序。应用在启动时将100000+ json行导入CoreData。
我使用批处理(250项)和NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
来分批写入数据库,而不阻塞主线程。
这些导入的数据应显示在表格视图中,并且用户将能够在导入过程中平滑滚动表格视图。
以前,我曾尝试使用.mainQueueConcurrencyType
作为NSFetchedResultsController的上下文,但是在合并其他私有上下文时,它会冻结滚动。(因为合并是在主线程上执行 )。
我创建了NSFetchedResultsController
以便在表视图中显示数据,并使用concurrencyType = .privateQueueConcurrencyType.
设置NSManagedObjectContext
所以NSFetchedResultsController
称它为
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
和func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>)
在后台线程上,并在后台线程上更改属性fetchedObjects
。
BUT func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
用于从主线程进行表视图调用。
因此fetchedObjects
可以随时更改(通过后台线程)而不依赖于主线程,因此它会产生崩溃。
(例如,当fetchedObjects
被删除并且现在包含0个元素,但是func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
可能具有先前的fetchedObjects.count
值。)
问题: 如何同步后台CoreData上下文的线程并从TableView的主线程访问数据?
代码:
class QuakesViewController: UITableViewController {
var tmpQuakes = [Quake]()
var changesStarted: Bool = false {
didSet {
tmpQuakes = changesStarted ? dataProvider.fetchedResultsController.fetchedObjects ?? [] : []
}
}
func getQuake(byIndexPath indexPath: IndexPath) -> Quake? {
return changesStarted ? tmpQuakes[indexPath.row] : dataProvider.fetchedResultsController.fetchedObjects?[indexPath.row]
}
func getCount() -> Int {
return changesStarted ? tmpQuakes.count : dataProvider.fetchedResultsController.fetchedObjects?.count ?? 0
}
}
// MARK: - UITableViewDataSource
extension QuakesViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "QuakeCell", for: indexPath) as? QuakeCell else {
print("Error: tableView.dequeueReusableCell doesn'return a QuakeCell!")
return QuakeCell()
}
guard let quake = getQuake(byIndexPath: indexPath) else { return cell }
cell.configure(with: quake)
return cell
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return getCount()
}
}
// MARK: - NSFetchedResultsControllerDelegate
extension QuakesViewController: NSFetchedResultsControllerDelegate {
/**
Reloads the table view when the fetched result controller's content changes.
*/
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
DispatchQueue.main.sync {
self.changesStarted = false
self.tableView.reloadData()
}
}
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
DispatchQueue.main.sync {
self.changesStarted = true
}
}
}
我可以在没有其他变量(例如tmpQuakes
和changesStarted
)的情况下进行同步吗?
与以下问题相同:CoreData child contexts, NSFetchedResultsController and main thread