Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Observing dependent keys across a to-many relationship

I have a Core Data entity, "bid", which has a relationship to many "items", called "itemLink".

in IB, I have a text field bound to "total", and that almost works.

In "bid.m" I have:

- (NSDecimalNumber *)total
{
    return [self valueForKeyPath:@"[email protected]"];
}

I also have:

+ (NSSet *)keyPathsForValuesAffectingTotal { 
    return [NSSet setWithObjects:@"itemLink", nil]; 

}

When adding or deleting an item, "total" updates as expected. But if you change an "item" within the set of itemLink, the total is not getting refreshed. How do you get KVO to see when a related object in the linked NSSet has changed?

Thanks

like image 880
AppCrafter Avatar asked Jun 01 '11 01:06

AppCrafter


2 Answers

It looks your problem is to do with the fact that keyPathsForValuesAffectingTotal only mentions the keyPath "itemLink".

Since that's the path of a to-many relationship, you're effectively telling your bid object to observe a set for changes. All that a set does is manage whether objects are members of it or not. So that explains why you get updates when items are added or removed from "itemLink", but only that.

You aren't just interested in which items are members of the set though, you're also interested in the (mutable) properties of those members -- price in this case. So in addition to the above, you want each member of "itemLink" to notify all observers of the relevant bid object's "total" key that "price" has changed whenever it changes.

Unfortunately, it's not as simple as adding "itemLink.price" as a dependent keypath in your Bid class, as KVO doesn't allow you to observe 'through' to-many relationships.

If you use a NSManagedObject subclass for instances of your Item entity, you could add this functionality manually. Override + automaticallyNotifiesObserversForKey: in your Item class to tell Cocoa you're going to manage KVO notifications manually for the "price" key, then implement your own setPrice: method that sends the appropriate notification. Something like this:

- (void)setPrice:(id)inPrice
{
    // bid = inverse relationship of itemLink
    [[self valueForKey:@"bid"] willChangeValueForKey:@"total"];
    [self willChangeValueForKey:@"price"];

    [self setPrimitiveValue:inPrice forKey:@"price"];

    [self didChangeValueForKey:@"price"];
    [[self valueForKey:@"bid"] didChangeValueForKey:@"total"];
}
like image 186
Chris Devereux Avatar answered Nov 16 '22 00:11

Chris Devereux


I wrote some code to support dependent keys across to-many relationships.

https://github.com/macoun/DerivedDependency

It also supports caching of calculated values.

like image 25
cocoafan Avatar answered Nov 16 '22 00:11

cocoafan