问题:使用.mainQueueConcurrencyType
线程处理核心数据时,UI被冻结
UI:任何UI updates
,UITable scrolling
等,但是在这个问题中,我使用SwiftSpinner
作为活动指示器的示例,
https://github.com/icanzilb/SwiftSpinner
设置:
iOS:11.4,设备:iPhone 7 plus,Xcode:9.4.1
我的代码如下
let bgContext = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
func doCoreData(progress : @escaping (Double) -> ()) {
bgContext.performAndWait {
for i in 1...10{
let cent : Double = Double(i)/Double(10)
// do some coredata work adding and updating
progress(cent)
// hide SwiftSpinner at the end
if i == 10 {
SwiftSpinner.hide()
}
}
}
}
func orgnizeThings (){
doCoreData { (cent) in
DispatchQueue.main.async {
let perCent = cent * 100
SwiftSpinner.show(progress: cent, title: "loading \(perCent)")
}
}
}
调用orgnizeThings()
函数将完成 Core Data 工作,但我想向用户展示该函数完成的程度
在此设置中,SwiftSpinner
UIView
被冻结
答案 0 :(得分:1)
核心数据不是线程安全的。如果同时写入多个线程,将并发类型从MainQueueConcurrencyType更改为PrivateQueueConcurrencyType可能导致应用程序崩溃。更好的方法是具有多个具有父子关系的管理对象上下文:
let mainMOC = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
let childMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
childMoc.parentContext = mainMoc
childMOC.performBlock{
for i in 1...10{
let cent : Double = Double(i)/Double(10)
// do some coredata work adding and updating
progress(cent)
}
do {
try childMoc.save()
mainMOC.performBlockAndWait{
do {
try mainMoc.save()
SwiftSpinner.hide()
} catch {
fatalError("Failure to save context: \(error)")
}
}
} catch{
fatalError("Failure to save context: \(error)")
}
}
保存子上下文后,更改将转到父上下文。保存父上下文后,更改将转到持久性存储协调器。主线程不会被阻塞,因为所有繁重的写操作都将在PrivateMcurrencyType的childMoc中完成。
如果性能仍然很差,那是因为从MainContext写入光盘是一项昂贵的操作。您可以创建一个将写入光盘的主上下文,而不是直接将父上下文写入光盘,一旦保存了主上下文,主上下文更改将进入Maser上下文。
有关更多详细信息,请阅读以下中篇文章:https://medium.com/soundwave-stories/core-data-cffe22efe716