views:

305

answers:

1

I have a NSManagedObjectContext in which I have a number of subclasses of NSManagedObjects such that some are containers for others. What I'd like to do is watch a top-level object to be notified of any changes to any of its properties, associations, or the properties/associations of any of the objects it contains.

Using the context's 'hasChanges' doesn't give me enough granularity. The objects 'isUpdated' method only applies to the given object (and not anything in its associations). Is there a convenient (perhaps, KVO-based) was I can observe changes in a context that are limited to a subgraph?

+3  A: 

You will want to listen for the NSManagedObjectContextObjectsDidChangeNotification to pick up all changes to your data model. This can be done using code like the following:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleDataModelChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:myManagedObjectContext];

which will trigger -handleDataModelChange: on any changes to the myManagedObjectContext context.

Your -handleModelDataChange: method would look something like this:

- (void)handleDataModelChange:(NSNotification *)note;
{
    NSSet *updatedObjects = [[note userInfo] objectForKey:NSUpdatedObjectsKey];
    NSSet *deletedObjects = [[note userInfo] objectForKey:NSDeletedObjectsKey];
    NSSet *insertedObjects = [[note userInfo] objectForKey:NSInsertedObjectsKey];

    // Do something in response to this
}

As you can see, the notification contains information on which managed objects were updated, deleted, and inserted. From that information, you should be able to act in response to your data model changes.

Brad Larson
Thanks! I wasn't aware of that notification. It still seems like massive overkill to have to perform a search each time the notification is sent. That said, I'm not sure how it could be optimized even by Apple; fundamentally, it's still a graph traversal.
D Carney
If you use an NSPredicate to filter through these objects it is actually quite performant because everything is in memory. I use this solution in several applications for the iPhone and there has yet to be a performance bottleneck in this area.
Marcus S. Zarra
Ah, good call on using an NSPredicate. Hadn't thought of that.
D Carney
You can also use notification `NSManagedObjectContextDidSaveNotification` to filter the changes after each save to the context.
krasnyk
Careful: The objects in the NSNotification's userInfo dictionary are actually of type NSSet and NOT NSArray!
racha
@racha - Good catch. I'd somehow screwed that up when copying code over. I've corrected the sample code in the answer.
Brad Larson