My application makes a lot of heavy conversions from some format to NSManagedObject
, so best way to me is to use NSOperation
(or Operation
in Swift 3) to make conversions from raw data to NSManagedObject
and after all operations are finished save that context.
I can't use separate context for each Operation
, because I my converter generates relationships (and they can be accessed only from same context) and application may run up to 20 conversions, so it's not cool to create new context and save it after each conversion.
So I need do create separate OperationQueue
and ensure that all operations inside it are performed from same thread as context, I don't know how to do it.
I have only one mind: start everything inside Operation.main()
as context.perform { }
, but I don't really think that it is good solution.
I've found similar thread at Stackoverflow, but answers are outdated and I see that accepted answer is not clearly right.
The best way I've found to use Core Data in Operation
is to make child context with privateQueueConcurrencyType
without any additional .perform
blocks (that private operation is already created in needed thread). I'm open to any other suggestions.
I've used operationQueue.maxConcurrentOperationCount = 1
to ensure safety and absence of merging conflicts, but I may propose that approach will work with concurrent operations, but it will be useless in most cases because operations will wait each while other context is not merged.
Be carefull about using waitUntilAllOperationsAreFinished()
in the same thread as parentContext
, in most cases that will cause deadlock.
class ExampleOperation: Operation {
let parentContext: NSManagedObjectContext
init(parentContext: NSManagedObjectContext) {
self.parentContext = parentContext
super.init()
}
override func main() {
if self.isCancelled { return }
let childContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
childContext.parent = parentContext
// use here `childContext` context directly
// e.g.: let result = try childContext.fetch(fetchRequest)
try? childContext.save()
}