Apple 向我们展示了如何使用后台线程执行繁重的写入操作(通过使用newBackgroundContext
)在他们的官方地震例子中 -https://github.com/yccheok/earthquakes-WWDC20 https://github.com/yccheok/earthquakes-WWDC20
但是,对于大量的读操作呢? (数百万行用于压力测试目的)
当我们第一次启动应用程序并且应用程序正在从 CoreData 读取大量数据时,我们还希望我们的应用程序 UI 具有响应能力。
以下是使用的代码片段NSFetchedResultController
.
如果有很多行,UI 就没有响应能力
let controller = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: persistentContainer.viewContext,
sectionNameKeyPath: nil, cacheName: nil)
controller.delegate = fetchedResultsControllerDelegate
// Perform the fetch.
do {
// This statement tooks some time to complete if you have a lot of rows.
try controller.performFetch()
} catch {
fatalError("Unresolved error \(error)")
}
如果有很多行,UI 就没有响应能力
我们尝试去表现controller.performFetch()
使用后台线程。尽管如此,但不知道为什么,用户界面仍然没有响应能力。我的猜测是,之后NSFetchedResultsController
占用UI主线程,执行一些耗时的I/O读操作。
let controller = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: persistentContainer.viewContext,
sectionNameKeyPath: nil, cacheName: nil)
controller.delegate = fetchedResultsControllerDelegate
DispatchQueue.global(qos: .background).async {
// Perform the fetch.
do {
// This statement tooks some time to complete if you have a lot of rows.
try controller.performFetch()
} catch {
fatalError("Unresolved error \(error)")
}
}
UI 现在已响应。但解决方案是错误的...
我想,我们需要放置NSFetchedresultController
也在后台线程下。因此,我们进行如下修改。
let backgroundContext = persistentContainer.newBackgroundContext()
let controller = NSFetchedResultsController(fetchRequest: fetchRequest,
managedObjectContext: backgroundContext,
sectionNameKeyPath: nil, cacheName: nil)
controller.delegate = fetchedResultsControllerDelegate
backgroundContext.perform {
// Perform the fetch.
do {
// This statement tooks some time to complete if you have a lot of rows.
try controller.performFetch()
} catch {
fatalError("Unresolved error \(error)")
}
}
UI 在获取过程中具有响应能力,一段时间后即可获取并显示数据。
但是,如果我们使用启动参数进一步调查
-com.apple.CoreData.ConcurrencyDebug 1
之后我们会遇到如下崩溃controller.performFetch()
完成执行。
CoreData`+[NSManagedObjectContext __Multithreading_Violation_AllThatIsLeftToUsIsHonor__]:
我想知道,当我们使用时,是否有可能使 UI 响应式NSFetchedResultController
加载大量数据(根据测试,有几百万行)?能NSFetchedResultController
曾经在后台线程下操作过吗?