Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 6533137
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 25, 20262026-05-25T10:05:20+00:00 2026-05-25T10:05:20+00:00

I have a very strange problem with inverse relations in Core Data, and I

  • 0

I have a very strange problem with inverse relations in Core Data, and I have managed to reduce my problem to a minimal example, starting from a new project in xcode based on the window template with support for Core Data (i.e., there’s very little there).

Suppose we have a Core Data model with three entities: Department, Employee, and DepartmentSummary (some sort of entity representing some statistics about the department). For simplicity’s sake, we have only one-to-one relations:

DepartmentSummary   Department        Employee
---------------------------------------------------------
                    employee  <---->  department
department  <---->  summary

This is all there is in the model. In application:didFinishLaunchingWithOptions: we create an employee and a department and set up KVO:

NSManagedObject* employee = 
 [NSEntityDescription 
   insertNewObjectForEntityForName:@"Employee"
   inManagedObjectContext:[self managedObjectContext]];
[employee addObserver:self forKeyPath:@"department" options:0 context:nil];

NSManagedObject* department = 
  [NSEntityDescription 
    insertNewObjectForEntityForName:@"Department"
    inManagedObjectContext:[self managedObjectContext]];
[department setValue:employee forKey:@"employee"];

The purpose of the KVO handler is to create a summary for the department as soon as the employee’s department is set:

- (void) observeValueForKeyPath:(NSString *)keyPath 
                       ofObject:(id)object 
                         change:(NSDictionary *)change 
                        context:(void *)context 
{
     [self createSummary:object];
}

createSummary is simple: it creates a new summary object and associates it with the department, and then checks that the inverse relation from the department to the summary object is also set:

- (void) createSummary:(NSManagedObject*)employee 
{
    NSManagedObject* department = [employee valueForKey:@"department"];
    NSManagedObject* summary = 
     [NSEntityDescription 
       insertNewObjectForEntityForName:@"DepartmentSummary"
       inManagedObjectContext:[self managedObjectContext]];

    [summary setValue:department forKey:@"department"];

    NSAssert([department valueForKey:@"summary"] == summary, 
             @"Inverse relation not set");
}

This assertion fails. Indeed, if we print the department and summary objects after the summary’s department has been set, we get

entity: DepartmentSummary; 
    id: ..DepartmentSummary/..AA14> ; 
  data: { 
    department = "..Department/..AA13>";
  }

for the summary, as expected, but

entity: Department; 
    id: ..Department/..AA13> ; 
  data: {
    employee = "..Employee/..AA12>";
    summary = nil;
  }

for the department (with a nil summary). If however we delay the call to createSummary so that it doesn’t run until the next iteration of the runloop:

- (void) observeValueForKeyPath:(NSString *)keyPath 
                       ofObject:(id)object 
                         change:(NSDictionary *)change 
                        context:(void *)context 
{
     [self performSelector:@selector(createSummary:) 
                withObject:object 
                afterDelay:0];
}

then everything works as expected.

Delaying the assertion instead does not help: the inverse relation really does not get set in the object graph, though it does get set in the database (if you were to save the database, and restart the app, now all of a sudden the inverse relation appears).

Is this a bug in Core Data? Is this documented behaviour which I have missed? Am I using Core Data in ways it was not intended?

Note that the KVO handler gets called while Core Data is (automatically) setting an(other) inverse: we manually set the department’s employee field, Core Data automatically sets the employee’s department field, and that in turn triggers the KVO handler. Perhaps that is just too much for Core Data to handle 🙂 Indeed, when we set

[employee setValue:department forKey:@"department"];

instead, everything again works as expected.

Any pointers would be appreciated.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-25T10:05:21+00:00Added an answer on May 25, 2026 at 10:05 am

    This is a classic Core Data problem. The docs specifically state:

    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.

    However, in practice this is a bald-faced lie, in that it is unreliable.

    My answers to your questions is thus:

    Is this a bug in Core Data?

    YES.

    Is this documented behaviour which I have missed?

    NO.

    Am I using Core Data in ways it was not intended?

    NO.

    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:

    [department setValue:employee forKey:@"employee"];
    [employee setValue:department forKey:@"department"];
    

    ie, set the relationship inverse yourself whenever you change the relationship.

    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:

    1. It works 100% of the time.
    2. It makes the code more readable.

    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.

    I would also suggest adding a simple category to NSManagedObject:

    @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
    

    as in:

    [department setValue:employee forKey:@"employee" inverse:@"department"];
    

    there are a few cases to expand upon that category but I would handle, for example, deletion in a different fashion altogether.

    In short: handle all your own relationships explicitly every time. Core Data is not trustworthy in this regard.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have very strange problem with Doxygen: I used it to create documentation from
We have very strange problem, one of our applications is continually querying server by
I have a very strange problem. Under some elusive circumstances I fail to apply
I have a very strange problem, when I try to var_dump (or print_r )
I have a very strange problem with the Delphi 2006 IDE. If the IDE
I use the memcache extension for python, and I have a very strange problem.
Im having a very strange problem, i have a complicated view that returns incorrect
We have encountered a very strange class not found problem in our web app
The problem seems very strange. I have a AJAX helper function within a same
Have a very strange problem with Apache .htaccess URL Rewriting and Redirection. Here's my

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.