Inserting a new managed object in Core Data - iphone

I am new to Core Data and I feel that I don't get a hang of it. When you are going to create a new managed object you have to use the method that I pasted in at the bottom from the NSEntityDescription class.
Now is this object registered in the context, it is right? Why do you have the insertObject: in NSManagedContext then? It works without invoking that method after using the one in NSEntityDescription. Could somebody explain?
NSManagedContext
insertObject:
NSEntityDescription
+ (id)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context

You can create NSManagedObject with nil context and then decide whether you want to add it to context or not.
You may also like this: Is there a way to instantiate a NSManagedObject without inserting it?

Related

iPhone Core Data - How to remove NSManagedObject from context?

CustomManagedObject *newObject = (CustomManagedObject *)[NSEntityDescription insertNewObjectForEntityForName:#"Substation" inManagedObjectContext:[[DatabaseHelper instance] context]];
I make a new object, using the line above. However sometimes i dont want to save that object to permanent data store, i just want to remove it from context. Is there some kind of method like removeObject: object fromContext: context?
Did you check the documentation? The method is called deleteObject:
[[[DatabaseHelper instance] context] deleteObject:newObject];

CoreData Relationships Lazy Load?

When I have a CoreData entity named, say, 'Book', which has a one-to-one relationship with another entity ('Bookmark') would I need to insert both an instance of 'Book' and an instance of 'Bookmark' into a managed object context, and manually assign the relationship?
If I perform the following code to instantiate an instance of 'Book'...
Book *book = [NSEntityDescription insertNewObjectForEntityForName:#"Book" inManagedObjectContext:managedObjectContext];
Can I, or can I not, perform the following code to retrieve its bookmark without inserting an instance of 'Bookmark' into the same managed object context?
book.bookmark;
Will CoreData allocate a new instance of 'Bookmark' for me?
Before you ask me to try this and see for myself: I have. I'm either doing something wrong, or I'm meant to instantiate both instances of 'Book' and 'Bookmark' and assign the relationship manually. In my testing, the relationship has 'optional' unticked but is not attached to anything. Upon invoking the getter 'bookmark' on a 'book' instance, I receive 'nil'.
I'd like to be able to use my code above, as it will allow my controller objects to deal with the managed object context, while my model objects can ignore it entirely. From what I've read of CoreData, this seems to be the intended implementation. Please correct me if I'm wrong.
If a Book object always requires a Bookmark relationship, then you can write a custom getter method for the bookmark property that will insert a bookmark object when needed.
Xcode will generate most to the method for you. In the data model editor control-click on the bookmark and choose Copy Objective-C 2.0 Implementation to the clipboard. Then tweak something like this:
- (NSManagedObject *)bookmark
{
id tmpObject;
[self willAccessValueForKey:#"bookmark"];
tmpObject = [self primitiveBookmark];
[self didAccessValueForKey:#"bookmark"];
if (tmpObject==nil){
BookmarkMO *newBookmark=[NSEntityDescription entityForName:#"Bookmark" inManagedObjectContext:self.managedObjectContext];
newBookmark.book=self; //triggers kvo relationship assignment
tmpObject=newBookmark;
}
return tmpObject;
}
In my experience you have to create both entities and create the relationship yourself first.
something like this should be what you need:
Bookmark *bookmark = [NSEntityDescription insertNewObjectForEntityForName:#"Bookmark" inManagedObjectContext:managedObjectContext];
[book setBookmark: bookmark];

tableview coredata temporary object

I am using a tableview with data from coredata using nsfetchedresultscontroller. When the view loads i make a new entity using
SomeManagedObject *someManagedObject = [NSEntityDescription insertNewObjectForEntityForName:#"SomeManagedObject" inManagedObjectContext:self.managedObjectContext];
This way the new entity appears in my tableview. Now i want this entity to be only temporary, but when i edit some object inside the tableview and save the managedObjectContext the temporary entity will also get saved and i don't want that.
Is their a way to save one object only and not everything inside de managedObjectContext?
Is their some other way to make a temporary object for my tableview.
Any help would be very welcome.
Thanks
Ton
Create the new NSManagedObject with it's alloc init and pass nil instead of the NSManagedObjectContext. Then if you later decide you want that object to be permanent then set it's context. However this will not allow you to see it in a NSFetchedResultsController because it will not be associated with the context.
A better answer can be provided if you could explain what your ultimate goal is.
No, in a managedObjectContext saving is a all or nothing. What I do not know is what happens if you set the persistent store of the managed object to nil
- (void)assignObject:(id)object toPersistentStore:(NSPersistentStore *)store
If you then save the managedObjectContext this object should not be saved. It is just a guess, but tell me if it works ;-)
For temporary managed objects, create them with a 2nd managed object context (MOC). When you are finished, simply release the MOC without performing a save.
Look at the Adding a Book code in CoreDataBooks which uses the same approach to throw away the newly added object when the user cancels.

Can I create an new instance of my custom managed object class without going through NSEntityDescription?

From an Apple example, I have this:
Event *event = (Event*)[NSEntityDescription
insertNewObjectForEntityForName:#"Event"
inManagedObjectContext:self.managedObjectContext];
Event inherits from NSManagedObject. Is there a way to avoid this weird call to NSEntityDescription and instead just alloc+init somehow directly the Event class? Would I have to write my own initializer that just does that stuff above? Or is NSManagedObject already intelligent enough to do that?
NSManagedObject provides a method called initWithEntity:insertIntoManagedObjectContext:. You can use this to do a more traditional alloc/init pair. Keep in mind that the object this returns is not autoreleased.
I've run into the exact same problem. It turns out you can completely create an entity and not add it to the store at first, then make some checks on it and if everything is good insert it into the store. I use it during an XML parsing session where I only want to insert entities once they have been properly and entirely parsed.
First you need to create the entity:
// This line creates the proper description using the managed context and entity name.
// Note that it uses the managed object context
NSEntityDescription *ent = [NSEntityDescription entityForName:#"Location" inManagedObjectContext:[self managedContext]];
// This line initialized the entity but does not insert it into the managed object context.
currentEntity = [[Location alloc] initWithEntity:ent insertIntoManagedObjectContext:nil];
Then once you are happy with the processing you can simply insert your entity into the store:
[self managedContext] insertObject:currentEntity
Note that in those examples the currentEntity object has been defined in a header file as follows:
id currentEntity
To get it to work properly, there is a LOT of stuff to do. -insertNewObject:... is by far the easiest way, weird or not. The documentation says:
A managed object differs from other
objects in three main ways—a managed
object ... Exists in an environment
defined by its managed object context
... there is therefore a lot of work
to do to create a new managed object
and properly integrate it into the
Core Data infrastructure ... you are
discouraged from overriding
initWithEntity:insertIntoManagedObjectContext:
That said, you can still do it (read further down the page to which I linked) but your goal appears to be "easier" or "less weird". I'd say the method you feel is weird is actually the simplest, most normal way.
I found a definitive answer from More iPhone 3 Development by Dave Mark and Jeff LeMarche.
If it really bothers you that you use a method on NSEntityDescrpiton rather than on NSManagedObjectContext to insert a new object into an NSManagedObjectContext, you can use a category to add an instance method to NSManagedObjectContext.
Create two new text files called NSManagedObject-Insert.h and NSManagedObject-Insert.m.
In NSManagedObject-Insert.h, place the following code:
import <Cocoa/Cocoa.h>
#interface NSManagedObjectContext (insert)
- (NSManagedObject *)insertNewEntityWithName:(NSString *)name;
#end
In NSManagedObject-Insert.m, place this code:
#import "NSManagedObjectContext-insert.h"
#implementation NSManagedObjectContext (insert)
- (NSManagedObject *)insertNewEntityWithName:(NSString *)name
{
return [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:self];
}
#end
You can import NSManagedObject-Insert.h anywhere you wish to use this new method. Then replace the insert calls against NSEntityDescription, like this one:
NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
with the shorter and more intuitive one:
[context insertNewEntityWithName:[entity name]];
Aren't categories grand?

iPhone Core Data: Initializing Managed Object without a context

Is there a way to initialize a managed object outside of a context. I'm basically trying to alloc/init a Managed Object outside of a context first, then figure out if I really want to insert the object, and then inject it into the datastore using an existing managed object context.
Is this possible, or does it go against the intended usage of Core Data?
Managed Object are "managed" by the context, therefore you cant really instanciate them with alloc since they are not meant to be.However, instantiating a managed object through the context does not persist it until you call save method on the context, so you would have the same effect using the context to instanciate it and only saving after you figure out that you really want to use the object.
No, you cannot instantiate an NSManagedObject instsance outside of an NSManagedObjectContext (well, you can, but bad things will happen and your program will almost certainly not work as you'd hoped). You can, however, create an NSInMemoryPersistentStore-backed NSManagedObjectContext. It's slightly more setup (not much) and everything vanishes when you dealloc the in-memory store. In the mean time, you get all the benefits of Core Data's object graph management.
For anyone who stumbles upon this question, here's how I accomplished what the OP was probably going for:
NSManagedObjectContext *moc = AppDelegate.managedObjectContext;
NSEntityDescription *entity = [NSEntityDescription entityForName:#"MyModel"
inManagedObjectContext:moc];
MyModel *model = [[MyModel alloc] initWithEntity:entity
insertIntoManagedObjectContext:nil];
What you are probably shooting for is multiple contexts. You can create an additional "scratchpad" context and then merge any changes back into the main context. One of Apple's iPhone sample projects accomplishes this exact thing. You'll have to log into the dev center to find it.