Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data keyPathsForValuesAffectingValueForKey only calling relationships, not attributes

I am using Core Data to model an entity which has both attributes and relationships. I would like to make one of the attributes dependent on two other relationships.

The Core Data FAQ and several other examples use +(NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key for this purpose. However, this only seems to be called for all of my relationship properties, but not for any of the attributes. In addition keyPathsForValuesAffecting<key> never gets called for any of my attributes.

Is this the normal behaviour or am I missing something? How can I calculate one attribute based on other attributes or properties, eg. a distance, by setting a startLocation and a stopLocation?

like image 981
Bram De Geyter Avatar asked Mar 25 '13 15:03

Bram De Geyter


1 Answers

It looks like a found the solution to my own problem after a couple of days and it turns out I was missing something.

After rereading the discussion of the method keysPathsForValuesAffectingValueForKey: in the NSKeyValueObserving Protocol Reference, I realized the meaning of the following sentence:

When an observer for the key is registered with an instance of the receiving class, key-value observing itself automatically observes all of the key paths for the same instance, and sends change notifications for the key to the observer when the value for any of those key paths changes.

In short, your instance should have an observer observing changes to your attribute <key>:

[myInstance addObserver:myObserver forKeyPath:attributeKey options:nil context:nil];

As soon as you have an observer registered, the protocol will call keysPathsForValuesAffectingValueForKey for your specific attribute key. If this method returns a non-empty set of key paths, KVO will emit a change notification for your attribute, if a change is made to any of these key paths, in addition to notifying you of any direct change to your attribute.

Relationship keys do get called automatically, because Core Data already uses observers to keep inverse relationships up to date.

In the particular case where you want to have an attribute depend on another attribute or relationship within the same entity, you will have to:

  1. Add an observer in the awakeFromInsert: method using addObserver:forKeyPath:options:context:
  2. Implement keyPathsForValuesAffectingValueForKey: or keyPathsForValuesAffecting<key>
  3. Implement observeValueForKeyPath:ofObject:change:context for your attribute key path to act on the relevant change notifications, i.e. updating your attribute value.
like image 131
Bram De Geyter Avatar answered Sep 21 '22 14:09

Bram De Geyter