An -awakeFromInsert gotcha

Imagine you’ve got a Core Data model where an entity has a one-to-one relationship with another. Say, “ObjectA” and its “Partner”. You expect a pair of these objects to be hooked up at all times. So you make life easy for yourself and create the partner automatically:

Well, don’t do this!

If you’re looking at using the new parent/child contexts feature in Core Data, the shortcut above will seriously trip you up. What the docs don’t mention is that when saving a child context, the process goes something like this:

  1. Copies of any new objects from the child context are inserted into the parent context. They share the same ID, but are two different objects (as you’d expect!), one for each context
  2. The insertion calls -awakeFromInsert to be called on the new objects in the parent context
  3. Attributes and relationships are applied to the objects in the parent context so that they match the child context

If your custom -awakeFromInsert method happens to insert objects of its own, as in the example above, that code is going to run for a second time and create an extra object that is about to be orphaned by step 3. Depending on your  model’s validation rules, you’ll then see this show up as either the parent context failing to save, or mysterious extra objects appearing!

The docs do state:

If you want to set attribute values in an implementation of this method, you should typically use primitive accessor methods

I’m inclined to read between the lines and reason thusly:

  1. Setting up a relationship using the primitive setter method is no good since Core Data won’t maintain the inverse of the relationship
  2. So I should use the proper setter method instead
  3. But the docs tell me to use primitive setters in -awakeFromInsert (albeit for attributes)
  4. So maybe I better just not do anything involving relationships there

On the other hand, the Core Data Programming Guide does have this to say:

Change processing is explicitly disabled around awakeFromFetch so that you can conveniently use public set accessor methods without dirtying the object or its context. This does mean, however, that you should not manipulate relationships, as changes will not be properly propagated to the destination object or objects. Instead, you can override awakeFromInsert

So that does seem to suggest that working with relationships from -awakeFromInsert is OK! Who to trust? I don’t know. Just make sure my example doesn’t bite you. And yes, I filed rdar://11119484 asking for the docs to mention this.

© Mike Abdullah 2007-2013