Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Undoing Core Data insertions that are performed off the main thread

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:

  1. Only objectID should be passed between managed object contexts (on separate threads)
  2. 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

like image 892
chockenberry Avatar asked Feb 09 '11 02:02

chockenberry


People also ask

Can we use Core Data managed objects from background thread?

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.

What is the purpose of NSManagedObjectContext?

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.

What is NSManagedObjectContext in Core Data?

An object space to manipulate and track changes to managed objects.

Is Managedobjectcontext thread safe?

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.


1 Answers

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:

  1. Change your background object creation to

    NSEntityDescription *myEntity = ... //Entity from your context
    [[NSManagedObject alloc] initWithEntity:myEntity
             insertIntoManagedObjectContext:nil];
    
  2. Store these entities in an array.
  3. Pass the entities back to your main thread as needed.
  4. Release on any objects you don't want to keep
  5. Call [myMainContext insertObject:managedObject] on any you want to keep.
  6. Perform a save on the 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.

like image 178
Marcus S. Zarra Avatar answered Oct 12 '22 04:10

Marcus S. Zarra