Reputation: 149
Problem: UI is frozen while working with core data with .mainQueueConcurrencyType
thread
UI: Any UI updates
, UITable scrolling
etc, But in this question I use example of SwiftSpinner
which is activity indicator,
https://github.com/icanzilb/SwiftSpinner
setup :
iOS : 11.4 , device : iPhone 7 plus, Xcode: 9.4.1
my code looks like this
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)")
}
}
}
calling the orgnizeThings()
function will get the Core Data work done but I would like to to show the user how far the function is done
in this setup the SwiftSpinner
UIView
is frozen
Upvotes: 1
Views: 1143
Reputation: 2040
Core data is not thread safe. Changing the concurrency type from MainQueueConcurrencyType to PrivateQueueConcurrencyType can cause the app to crash if multiple threads are writing at the same time. Better approach would be to have multiple manage object contexts, with parent child relationship:
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)")
}
}
When the child context is saved, the changes go to the parent context. When the parent context is saved, changes go to the persistent store coordinator. The main thread won't be blocked, because all the heavy write operations will be done in the childMoc which is of PrivateConcurrencyType.
If the performance is still poor, it would be because writing from MainContext to disc is an expensive operation. Instead of parent context writing to the disc directly, you can create a master context which will write to the disc and Main context changes will go to Maser Context once the Main Context is saved.
For more details, read this medium post: https://medium.com/soundwave-stories/core-data-cffe22efe716
Upvotes: 4