Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>This is a classic Core Data problem. The docs specifically state:</p> <blockquote> <p>Since Core Data takes care of the object graph consistency maintenance for you, you only need to change one end of a relationship and all other aspects are managed for you. </p> </blockquote> <p>However, in practice this is a bald-faced lie, in that it is unreliable.</p> <p>My answers to your questions is thus:</p> <blockquote> <p>Is this a bug in Core Data?</p> </blockquote> <p>YES.</p> <blockquote> <p>Is this documented behaviour which I have missed? </p> </blockquote> <p>NO.</p> <blockquote> <p>Am I using Core Data in ways it was not intended?</p> </blockquote> <p>NO.</p> <p>You have already provided the "correct" solution to your problem, the same solution which I use every single time I change relationship values in every single Core Data app I make. For literally hundreds of cases, the recommended pattern is:</p> <pre><code>[department setValue:employee forKey:@"employee"]; [employee setValue:department forKey:@"department"]; </code></pre> <p>ie, set the relationship inverse yourself whenever you change the relationship.</p> <p>Someone may have more light on this subject, or a more canon form for working around your issue, but in my experience there is no way to guarantee that a relationship is actively available unless it is manually established (as your problem shows). More importantly, this solution also has two other benefits:</p> <ol> <li>It works 100% of the time.</li> <li>It makes the code more readable.</li> </ol> <p>The last point is counter-intuitive. On the one hand, it seems to complicate the code and make it longer by adding lines to what could be, according to the docs, a short, one-line call. But in my experience what it does is save a trip by the programmer to the Core Data editor to visually hunt down and confirm model relationships, which is more valuable time-wise. It's better to be clear and explicit vs having a mental-model of what is supposed to happen when changing a relationship.</p> <p>I would also suggest adding a simple category to NSManagedObject:</p> <pre><code>@interface NSManagedObject (inverse) - (void)setValue:(id)value forKey:(NSString *)key inverseKey:(NSString *)inverse; @end @implementation NSManagedObject (inverse) - (void)setValue:(id)value forKey:(NSString *)key inverseKey:(NSString *)inverse { [self setValue:value forKey:key]; [value setValue:self forKey:inverse]; } @end </code></pre> <p>as in:</p> <pre><code>[department setValue:employee forKey:@"employee" inverse:@"department"]; </code></pre> <p>there are a few cases to expand upon that category but I would handle, for example, deletion in a different fashion altogether.</p> <p><strong>In short:</strong> <em>handle all your own relationships explicitly every time.</em> Core Data is not trustworthy in this regard.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. COHmmm. Interesting. I have found it's more than just when setting relations though. A similar problem happens when deleting a record; the inverse relation might not be set to nil. Do you deal with that manually too? I would be worried that I'll start missing cases. For now, I have made sure that I never change the object graph in a KVO handler; I compute what needs to be done and then schedule it for the next iteration of the runloop. This works, but I have to admit this out-of-order execution makes the code more complicated.
      singulars
    2. COYes, when deleting, I always set relationships to nil manually. In my experience Core Data does reliably schedule objects for deletion according to the rules stated in the docs, so that is not a problem. To clarify, Core Data in fact does everything it states, only that it does certain operations "when convenient" rather than "right now", as you discover in your code. If you need a relationship available asap, you should set it yourself. If you only need it the next time the runloop sets up your UI, let the automated system handle it.
      singulars
    3. COAlso, I would, if I were you, go back to altering relationships in KVO handlers. This is totally normal. I would *not* go about inventing my own runtime for Core Data change propagation. The real insight here is understanding that you need to manage relationships manually, not that you need to "wait" and then handle changes later.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload