How to work with temporary instances of NSManagedObject?

I need to create NSManagedObject instances, do something with them, and then delete them or save to sqlite db. The problem is that I cannot create instances of NSManagedObject unconnected to NSManagedObjectContext , and that means I have to somehow clear up after deciding that I don't need some of the objects in my db.

To handle this, I created a storage in memory using the same coordinator, and I place temporary objects there using assignObject:toPersistentStore. Now, how can I guarantee that these temporary objects do not fall into the data that I get from the general context of both stores? Or do I need to create separate contexts for such a task?




UPD:

Now I'm thinking of creating a separate context for storage in memory. How to move objects from one context to another? Just using [context insertObject:]? Will it work fine in this setting? If I insert one object from the object graph, is the entire graph also inserted in the context?

+82
objective-c iphone core-data
Jul 15 '10 at 13:56
source share
8 answers

The easiest way to do this is to create instances of NSManagedObject without the associated NSManagedObjectContext .

 NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC]; NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; 

Then when you want to save it:

 [myMOC insertObject:unassociatedObject]; NSError *error = nil; if (![myMoc save:&error]) { //Respond to the error } 
+141
Jul 15 2018-10-15T00:
source share

iOS5 provides a simpler alternative to Mike Weller's answers. Use the child NSManagedObjectContext instead. This eliminates the need for a trampoline through NSNotificationCenter.

To create a child context:

 NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; childContext.parentContext = myMangedObjectContext; 

Then create your objects using the child context:

 NSManagedObject *o = [NSEntityDescription insertNewObjectForEntityForName:@"MyObject" inManagedObjectContext:childContext]; 

Changes apply only while maintaining the child context. Therefore, to discard changes, just do not save.

There is still a relationship restriction. those. You cannot create relationships with objects in other contexts. To get around this, use objectID to get the object from the child context. eg.

 NSManagedObjectID *mid = [myManagedObject objectID]; MyManagedObject *mySafeManagedObject = [childContext objectWithID:mid]; object.relationship=mySafeManagedObject; 

Note. Saving the child context will apply the changes to the parent context. Saving the parent context saves the changes.

For a full explanation, see wwdc 2012 session 214 .

+36
Jan 24 '13 at 4:43
source share

The right way to achieve this kind of thing is the new context of the managed entity. You create a managed object context with the same persistent storage:

 NSManagedObjectContext *tempContext = [[[NSManagedObjectContext alloc] init] autorelease]; [tempContext setPersistentStore:[originalContext persistentStore]]; 

Then you add new objects, mutate them, etc.

When the time comes to save, you need to call [tempContext save: ...] in tempContext and process the save notification to merge this into the original context. To drop objects, just release this temporary context and forget about it.

Therefore, when you save the temporary context, the changes are saved in the repository, and you just need to return these changes to your main context:

 /* Called when the temp context is saved */ - (void)tempContextSaved:(NSNotification *)notification { /* Merge the changes into the original managed object context */ [originalContext mergeChangesFromContextDidSaveNotification:notification]; } // Here where we do the save itself // Add the notification handler [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tempContextSaved:) name:NSManagedObjectContextDidSaveNotification object:tempContext]; // Save [tempContext save:NULL]; // Remove the handler again [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:tempContext]; 

It is also a way to handle multi-threaded operations with master data. One context for the thread.

If you need access to existing objects from this temporary context (to add relationships, etc.), you need to use the object identifier to get a new instance, for example:

 NSManagedObject *objectInOriginalContext = ...; NSManagedObject *objectInTemporaryContext = [tempContext objectWithID:[objectInOriginalContext objectID]]; 

If you try to use NSManagedObject in the wrong context, you will get exceptions when saving.

+9
Jul 15 '10 at 14:37
source share

Creating temporary objects from a nil context works fine until you actually try to establish a relationship with an object whose context is: = nil!

make sure everything is in order.

+9
Feb 03 2018-12-12T00:
source share

What you are describing is exactly what NSManagedObjectContext for.

From Master Data Programming Guide: Basic Data Fundamentals

You can view the context of a managed entity as an intelligent notebook. When you retrieve objects from a permanent storage, you bring temporary copies to a notepad, where they form a graph of objects (or a set of graphs of objects). Then you can change the objects that you like. However, if you do save these changes, persistent storage remains unchanged.

And Master Data Programming Guide: Validating a Managed Object

It also reinforces the idea of โ€‹โ€‹the context of the managed entity representing the โ€œscratch padโ€ โ€”in general, you can transfer the managed entities to a notepad and edit them however you want before making changes or discarding them.

NSManagedObjectContext are light weight. You can create and discard them at your discretion - this is the permanent coordinator of stores, and its dependencies are "heavy". A single persistent storage coordinator can have many contexts associated with it. According to the outdated obsolete model of thread restriction, this means installing the same persistent storage coordinator in each context. Today, this would mean merging the nested contexts into the root context associated with the permanent repository coordinator.

Create a context, create and modify managed objects in this context. If you want to save them and report these changes, save the context. Otherwise, discard it.

An attempt to create managed objects independent of NSManagedObjectContext asks for problems. Remember that Core Data is ultimately a change tracking mechanism for an object graph. Because of this, managed objects are indeed part of the context of a managed object . The context respects their life cycle, and without context, not all functions of the managed object will work correctly.

+8
Aug 15 '14 at 10:33
source share

Depending on your use of the temporary object, there are some caveats to the above recommendations. My use case is that I want to create a temporary object and bind it to the views. When the user chooses to save this object, I want to establish relationships with existing objects and save. I want to do this in order to avoid creating a temporary object to store these values. (Yes, I can just wait for the user to save and then capture the contents of the view, but I put these views inside the table, and the logic for this is less elegant.)

Parameters for temporary objects:

1) (Preferred) Create a temporary object in the child context. This will not work because I bind the object to the user interface, and I cannot guarantee that the accessors of the object are called in the child context. (I did not find documentation that says otherwise, so I have to assume.)

2) Create a temporary object with the context of the nil object. This does not work and leads to data loss / corruption.

My solution: I solved this by creating a temporary object with an nil object context, but when I save the object and not paste it as # 2, I copy all its attributes to the new object that I create in the main context. I created a helper method in my subclass of NSManagedObject called cloneInto: this allows me to easily copy attributes and relationships for any object.

+6
Feb 09 '15 at 19:08
source share

For me, Marcus's answer did not work. Here is what worked for me:

 NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC]; NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil]; 

then if I decide to save it:

 [myMOC insertObject:unassociatedObjet]; NSError *error = nil; [myMoc save:&error]; //Check the error! 

We also must not forget to release it.

 [unassociatedObject release] 
+1
Jul 28 2018-11-11T00:
source share

I rewrite this answer for Swift as all similar questions to quickly redirect to this question.

You can declare an object without a ManagedContext using the following code.

 let entity = NSEntityDescription.entity(forEntityName: "EntityName", in: myContext) let unassociatedObject = NSManagedObject.init(entity: entity!, insertInto: nil) 

Later, to save the object, you can insert it into the context and save it.

 myContext.insert(unassociatedObject) // Saving the object do { try self.stack.saveContext() } catch { print("save unsuccessful") } } 
0
Nov 17 '17 at 10:49 on
source share



All Articles