views:

85

answers:

4

This is an iPhone dev question about CoreData.

I have a user interface to insert a Transaction. once the user clicks on a plus he gets the screen and i want to instantiate my Core Data NSManagedObject entity let the user work on it. Then when the user clicks on the Save button i will call the save function.

so down to code:

    transaction = (Transaction *)[NSEntityDescription insertNewObjectForEntityForName:@"Transaction" inManagedObjectContext:self.managedObjectContext];
//even if i dont call save: its going to show up on my table
[self.managedObjectContext save:&error]

P.S i am using an NSFetchedResultsController on that table and I see that the NSFetchedResultsController is inserting a section and an object to the table.

My thought is if there is a way to instantiate the Transaction NSManagedObject i could update it with out saving untill the client choses to.

Any help appreciated, Thanks.

+3  A: 

You can insert an NSManagedObjectContext with the -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:], passing nil for the managed object context. You must, of course, assign it to a context (using -[NSManageObjectContext insertObject:] before saving. This is, as far as I know, not really the intended pattern in Core Data, however (but see @mzarra's answer here). There are some tricky ordering issues (i.e. making sure the instance gets assigned to a context before it expects to have one, etc.). The more standard pattern is to create a new managed object context and insert your new object into that context. When the user saves, save the context, and handle the NSManagedObjectDidSaveNotification to merge the changes into your 'main' context. If the user cancels the transaction, you just blow away the context and go on with your business.

Barry Wark
I think you mean `NSManagedObject`, not `NSManagedObjectContext`. Either way, it doesn't look like you can change the MOC a NSManagedObject is associated with — you might be confusing it with `-[NSManagedObjectContext assignObject:toPersistentStore:]`.
tc.
@tc, thanks for the typo catch.
Barry Wark
+2  A: 

For what it's worth, Marcus Zarra seems to be promoting the nil context approach, claiming that it's expensive to create a new context. For more details, see this answer to a similar question.

James Huddleston
Hi this worked for a while until i tried to establish a relationship between my transaction and a category NSManagedObject. then the app crashed because of that. Is there any way around it ?
Cocoa student
If you need to set up relationships, I'd go with the two context approach. As tc. points out, objects in different contexts aren't supposed to reference each other. On the other hand, you could postpone setting those relationships until *after* you insert the new unassociated object into your main context.
James Huddleston
+2  A: 
tc.
Hi @tc. i tried the first response which is to insertIntoManagedObjectContext:nil but then when i wanted to assign a relationship the app crashed with error: reason: 'Illegal attempt to establish a relationship 'category' between objects in different contexts. so i guess my question is since its not legal to make a relationship between a context NSManaged object and an out of context managed object, what would be the solution ?
Cocoa student
I ended up creating a category entity the same way with no context but when it came to saving i added both to the context and then it worked well.
Cocoa student
A: 

here is how i worked it out:

On load, where we know we are dealing with a new transaction, i created an out of context one.

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Transaction" inManagedObjectContext:self.managedObjectContext];
        transaction = (Transaction *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];

then when it came to establishing a relation ship i did this:

if( transaction.managedObjectContext == nil){
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Category" inManagedObjectContext:self.managedObjectContext];
        Category *category = (Category *)[[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
        category.title = ((Category *)obj).title;
        transaction.category = category;
        [category release];
    }
    else {
        transaction.category = (Category *)obj;
    }

and at the end to save:

if (transaction.managedObjectContext == nil) {
        [self.managedObjectContext insertObject:transaction.category];
        [self.managedObjectContext insertObject:transaction];
    }
    //NSLog(@"\n saving transaction\n%@", self.transaction);

    NSError *error;
    if (![self.managedObjectContext save:&error]) {
        // Update to handle the error appropriately.
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }
Cocoa student