glenc
glenc

Reputation: 3172

Detecting many-to-many relationship changes in CoreData

We have a pretty robust and fleshed-out system for detecting changes on the models in our iOS app using NSManagedObjectContextObjectsDidChangeNotification. This works well for our attribute changes as well as changes in 1:1 and 1:M relationships.

We're trying to build in some M:M relationships to our schema now and I'm struggling to see how Coredata's notification system will allow us to observe specific changes in M:M relationships.

I'm guessing that if a M:M relationship changed, the two objects involved in the change would both appear in the NSUpdatedObjectsKey list, but there wouldn't be any specific annotation to say that a M:M relationship between them had changed, or which M:M relationship that was (assuming there are possibly more than one M:M relationship between two models).

Has anyone had any luck in using Coredata's notifications system to detect changes in M:M relationships? Or are they basically difficult to work with and people tend to resort to explicitly creating the "joining table" as a real type (and thereby ending up with two 1:M relationships instead of a single M:M relationship)?

Upvotes: 1

Views: 1161

Answers (1)

rgeorge
rgeorge

Reputation: 7327

You are correct: when a M:M relationship changes, the objects at both ends of the relationship show up in the appropriate dictionaries in the NSManagedObjectContextObjectsDidChangeNotification.

If you're scanning the objects looking for the specific properties that have changed, you can use the method changedValues (or, better, changedValuesForCurrentEvent on ios5) to find out the property names. You are probably already doing this.

You can then inspect the model to see if any given property is many:many or not:

-(void)notifyObjectsChanged:(NSNotification *)note
{
  assert([NSManagedObjectContextObjectsDidChangeNotification isEqual:note.name]);
  for (NSManagedObject *mo in [note.userInfo objectForKey:NSUpdatedObjectsKey])
  {
    NSLog(@"for %@ :", mo.objectID);
    NSDictionary *rels = mo.entity.relationshipsByName;
    for (NSString *prop in [mo.changedValuesForCurrentEvent allKeys])
    {
      NSRelationshipDescription *rel = [rels objectForKey:prop];
      if (rel.isToMany && rel.inverseRelationship.isToMany)
        NSLog(@"many-to-many relationship %@ changed", prop);
    }
  }
}

(untested, off the top of my head, watch for typos!)

The essential technique is that managed objects keep references to the object model description, which you can inspect at runtime.

Upvotes: 2

Related Questions