9

Possible Duplicate:
Store But Don't Save NSManagedObject to CoreData?

I need to make an NSManagedObject without saving it, how can I do this?

The reason I want to do this is the app has a setup in which the user enters their details, however I only want to save the object if they complete the setup (they have the option to cancel, in which case the object needs to be discarded without being saved, which is why I don't want to insert it straight away).

I have tried insetting one without a context but the app crashes.

I have tried the following:

GuestInfo *guest;
guest = (GuestInfo *)[NSEntityDescription insertNewObjectForEntityForName:@"GuestInfo" inManagedObjectContext:nil];

This causes the crash with the following error message:

'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'GuestInfo''
mfaani
  • 33,269
  • 19
  • 164
  • 293
Josh Kahane
  • 16,765
  • 45
  • 140
  • 253
  • why don't you show us your code? – vikingosegundo Apr 15 '12 at 22:18
  • 2
    What are you actually using this object for if you do not need to persist it? Can you not just create another object with the same interface? – Paul.s Apr 15 '12 at 22:49
  • If you want to insert an NSManagedObject then you need to have a context to put it in. However, I agree with @Paul.s – sosborn Apr 16 '12 at 00:01
  • The reason I want to do this is the app has a setup in which the user enters their details, however I only want to save the object if they complete the setup (they have the option to cancel, in which case the object needs to be discarded without being saved, which is why I don't want to insert it straight away). – Josh Kahane Apr 16 '12 at 10:40

4 Answers4

14

I would recommend creating the managed object and inserting into your managed object context as normal. You will have a reference to the managed object, i.e.:

GuestInfo* guest = (GuestInfo *)[NSEntityDescription insertNewObjectForEntityForName:@"GuestInfo" inManagedObjectContext:managedObjectContext];

Then if the user cancels, just delete it from the managed object context like this:

[guest deleteInContext:managedObjectContext];

The managed object context is designed as a scratchpad for you to create and delete objects in it like this.

Another option you might consider is calling:

[managedObjectContext rollback]

if the user cancels. i.e. you would create the managed object in the managed object context, but if the user cancels, you undo or rollback the state of the managed object context to how it was at the last time it was saved. See the "Undo Management" section of the Apple's "Using Managed Objects" doc:

https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CoreData/Articles/cdUsingMOs.html

Rob B
  • 1,485
  • 12
  • 16
7

Create a NSManagedObjectContext, as a child of your normal context. You can make all the changes in there that you want, and as long as you don't call save, the stuff in there will not get pushed.

For example...

NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType: NSPrivateQueueConcurrencyType];
moc.parentContext = myCurrentManagedObjectContext;

Now, from within any thread in your program, you can make the following call...

[moc performBlock:^{
    // Do anything you want to with this context... make a new object, whatever.
    // As long as you do not call [moc save], your changes will not propagate
    // up to the parent context, nor saved.
}];
mfaani
  • 33,269
  • 19
  • 164
  • 293
Jody Hagins
  • 27,943
  • 6
  • 58
  • 87
  • Forgive me Im new to CoreData, I have tried the first bit and I crash with: `'Parent NSManagedObjectContext must use either NSPrivateQueueConcurrencyType or NSMainQueueConcurrencyType.'`. Then, trying that method I get an error saying there is no visible interface fir the context which declares performWork. – Josh Kahane Apr 15 '12 at 22:42
  • You need to provide more information then. Specifically, how are you creating your "current" MOC? If you are doing it with just alloc/init, try creating it with alloc/initWithCurrencyType: NSMainQueueConcurrencyType which will be just fine, if your app is only using the main thread anyway. Regarding performWork.. type. I fixed it in the answer. – Jody Hagins Apr 15 '12 at 23:48
  • **This.** Using a private context to create possibly transient managed objects is a much better solution than inserting the object into the main context and then deleting it if it's not needed (as the currently accepted answer suggests). In addition to a clean design you get a lot of other benefits from this approach as well. – memmons Mar 19 '13 at 22:05
0

Managed objects always need to have a context. If you don't want the objects to be persistent, simply don't save the context.

If you never want your objects to be persistent, it is questionable if you should actually use Core Data.

omz
  • 53,243
  • 5
  • 129
  • 141
  • If I must always use a context, then why would it be that when calling `insertNewObjectForEntityForName:inManagedObjectContext:` does it instantly add the object to CoreData just with null values? I want to create the object but not save it unless the user confirms to at a later stage. – Josh Kahane Apr 16 '12 at 10:42
  • So? Inserting an object in a managed object context does _not_ save it. You would have to do that explicitly by calling `save:`. – omz Apr 16 '12 at 15:06
  • 2
    I think this is wrong? When I use insertNewObjectForEntityForName:inManagedObjectContext and then (before calling save!) perform a fetch on coredata the object shows up. – Kevin Grabher May 20 '14 at 09:20
  • 1
    @KevinGrabher A fetch request can return objects that haven't been saved yet. To quote from the [`NSManagedObjectContext` docs](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/CoreDataFramework/Classes/NSManagedObjectContext_Class/NSManagedObjectContext.html#//apple_ref/occ/instm/NSManagedObjectContext/executeFetchRequest:error:): "An object that meets the criteria specified by request (...) and that has been inserted into a context but which is not yet saved to a persistent store, is retrieved if the fetch request is executed on that context." – omz May 20 '14 at 12:33
-1

It is a bit strange to make a Core Data object if you don't want to save it....but anyway the error says that you have no model file named GuestInfo included in your project. Verify that it exists and is included in your Copy Bundle Resources section. The model file is the one where you declare the types in your database and the connections between them.

borrrden
  • 33,256
  • 8
  • 74
  • 109
  • The reason for that error is actually that the `insertNewObjectForEntityForName:inManagedObjectContext:` method infers the model from its context parameter (which is `nil` here). That doesn't necessarily mean that the model file isn't present. – omz Apr 16 '12 at 01:02
  • @omz I mean it isn't present in the form that is being looked for...but I admit I did overlook that the context was nil ^^; – borrrden Apr 16 '12 at 01:15