Search code examples
ios5core-datansmanagedobjectnsmanagedobjectcontext

Bug in iOS coredata objectWithID when moving objects between contexts


I am observing a weird bug in iOS using core-data. Basically, my setup is as follows- Have 2 NSManagedObjectContexts, tempContext and mainContext. I use tempContext as a temporary 'scratchpad' for creating and editing entities, and when I want to save them, I move it to the mainContext to save. Note that mainContext is not the parent of tempContext.

The move happens as follows-

[1] newEntity.property1 = @"SomeProperty";
    newEntity.managedObjectContext // this is tempContext currently
[2] saveEntityInTempContext
[3] newEntity = (Entity *)[mainContext objectWithID:newEntity.objectID];
[4] [mainContext insertObject:newEntity];

Now, after insert[4], if I check newEntity.property1, it is set as nil. However, if I check the property first after [3] and then after [4], it shows it correctly as "SomeProperty". I don't understand how forcing faulting should make a difference here.

My goal is just to move an entity from one context to another.


Solution

  • I'm not sure what the immediate cause is, but it's almost certainly a weird side effect of an unnecessary step that really doesn't make any sense. I'm kind of surprised you don't get an exception in the last step.

    Specifically, step #4 is completely unnecessary. Once you finish step #3, you have an instance that was loaded from mainContext. You don't need to do anything more at that point. It doesn't make sense to call insertObject for an object that you just looked up from the same managed object context.

    Assuming that tempContext and mainContext use the same persistent store coordinator, the life cycle of this object proceeds as follows in your steps:

    1. newEntity is already created but not saved. tempContext knows about newEntity but the data store does not (and of course mainContext doesn't know about it).
    2. After saving, the data store has a record of newEntity. newEntity's object ID changes to a permanent value.
    3. As a result of your objectWithID: call, the instance of newEntity gets replaced with a different instance that was looked up via mainContext. It's attributes match the ones you created in step 1 and saved to the data store in step 2, because they were loaded from the data store.
    4. Calling insertObject serves no purpose-- because the new newEntity you got in step 3 was looked up from mainContext, meaning that mainContext already knows about it. This is where I would have expected an exception. No exception occurs, but the call still doesn't make sense.

    So, I'd just drop step #4 and be done with it.