Is it possible to receive a callback or notification in the parent Entity when any one it's relationship objects changes? This works great when an attribute of the Entity changes. The following method...
- (void)didChangeValueForKey:(NSString *)key
is invoked on my Entity subclass. However this method is not invoked when an attribute in one of the relationships changes.
What I'm trying to do is update the timeStamp attribute on my parent Entity when any one of its attributes or relationship objects changes.
The parent entity can set itself as an observer of the relationship and it will get notified when that relationship changes. However that will only be fired when the actual relationship (adding or removing a child) occurs.
To watch for a specific child entity is far more tricky. There are a couple of ways to go about it:
NSManagedObjectContextDidSaveNotification
and look to see if any of its children are in that saveThere may be other solutions but of the three I recommend #2. It is pretty easy to set up and the performance impact is pretty minimal.
In the other answer I found 1,2 and 3 too inefficient. Particularly 2 and the example in the "Parent Watching it's Child" blog post. My issue with that is every single parent had to respond to the context notification and essentially every object being saved if it is the child (never mind the fact ContextDidSave is more appropriate in that case!). Instead, I would propose an option 4:
My solution is more efficient and feels more object-oriented to me since the object that is changing is responding to its own change. To implement this, within the child object use:
-(void)didSave{
[super didSave];
// notify that the parent has changed.
[[NSNotificationCenter defaultCenter] postNotificationName:NSManagedObjectContextObjectsDidChangeNotification
object:self.managedObjectContext
userInfo:@{NSUpdatedObjectsKey : [NSSet setWithObject:self.parent]}];;
}
To update the parent timestamp, the following neat solution (second last post) I've been using might help, e.g. in the parent use:
- (void) awakeFromInsert
{
[super awakeFromInsert];
// set the default dates
NSDate* date = [NSDate date];
self.timestamp = date;
//allow any future modifications to change the timestamp
_finishedStartup = YES;
}
- (void) awakeFromFetch
{
[super awakeFromFetch];
// we should already have creation and modified dates.
_finishedStartup = YES;
}
- (void) didChangeValueForKey: (NSString *) thisKey
{
[super didChangeValueForKey: thisKey];
if(![thisKey isEqualToString:@"timestamp"] && // prevent infinite loop
![self isFault] &&
![[[self managedObjectContext] undoManager] isUndoing] &&
_finishedStartup) // ensures we arent being called by the object being loaded from fetched data.
{
self.timestamp = [NSDate date];
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With