I'm working on some code that uses an NSOperation
to import data. I'd like for the user to be able to undo the NSManagedObject
instances that are created during the import operation.
From what I can tell, it's impossible to use the NSManagedObjectContext
-undoManager
for any operations that are performed off of the main thread. From the Core Data Programming Guide section on Use Thread Confinement to Support Concurrency, we have these two conditions:
- Only objectID should be passed between managed object contexts (on separate threads)
- Managed objects must be saved in a context before the objectID can be used.
This makes sense since the managed objects need to be moved from private storage (NSManagedObjectContext
) to public storage (NSPersistentStore
) before they can be shared.
Unfortunately, the -save:
message also causes any managed objects in the undo stack to be removed. From the Memory Management Using Core Data section of the same guide:
Managed objects that have pending changes (insertions, deletions, or updates) are retained by their context until their context is sent a save:, reset , rollback, or dealloc message, or the appropriate number of undos to undo the change.
I've tried several things to work around this limitation, and everything eventually leads back to bulk of the work happening on the main thread (and spinning beach balls.) Any clues to getting undo working with objects created off the main thread would be very much appreciated.
--
An enhancement Radar has been submitted: rdar://problem/8977725
Core Data is designed to work in a multithreaded environment. However, not every object under the Core Data framework is thread safe. To use Core Data in a multithreaded environment, ensure that: Managed object contexts are bound to the thread (queue) that they are associated with upon initialization.
A managed object context is an instance of NSManagedObjectContext . Its primary responsibility is to manage a collection of managed objects. These managed objects represent an internally consistent view of one or more persistent stores.
An object space to manipulate and track changes to managed objects.
Managed Object ContextThe NSManagedObjectContext class isn't thread safe. Plain and simple. You should never share managed object contexts between threads. This is a hard rule you shouldn't break.
This answer will probably be a bit of a back and forth. If I understand the issue correctly, you are doing an import but when the import is done you want the user to be able to select what gets saved from the import?
If that is not correct, please fix my assumptions and I will update this answer.
If it is correct then what you can do is:
Change your background object creation to
NSEntityDescription *myEntity = ... //Entity from your context
[[NSManagedObject alloc] initWithEntity:myEntity
insertIntoManagedObjectContext:nil];
[myMainContext insertObject:managedObject]
on any you want to keep.NSManagedObjectContext
.Since these entities are not part of a NSManagedObjectContext
yet they only exist in memory and should be thread safe since they are not yet tied down to a NSManagedObjectContext
.
This is of course theoretical and will require testing. However it should accomplish your goal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With