keyPathsForValuesAffectingValueForKey: — doing it wrong

I just noticed this in the docs for the keyPathsForValuesAffectingValueForKey: method:

Your override should typically invoke super and return a set that includes any members in the set that result from doing that (so as not to interfere with overrides of this method in superclasses).

I've been doing it wrong. I've been doing it like this:

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
    if ([key isEqualToString:@"fullName"])
    {
        return [NSSet setWithObjects:@"firstName",
                                     @"lastName",
                                     nil];
    }
    else
    {
        return [super keyPathsForValuesAffectingValueForKey:key];
    }
}

It didn't occur to me that a superclass might also want to specify key paths that affect the fullName key. A correct implementation would have been:

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key
{
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
    NSArray *moreKeyPaths = nil;
 
    if ([key isEqualToString:@"fullName"])
    {
        moreKeyPaths = [NSArray arrayWithObjects:@"firstName",
                                                 @"lastName",
                                                 nil];
    }
 
    if (moreKeyPaths)
    {
        keyPaths = [keyPaths setByAddingObjectsFromArray:moreKeyPaths];
    }
 
    return keyPaths;
}

Serves me right for not reading the docs carefully. For pride's sake I was hoping this was a common mistake, but from a Google search it seems almost everybody else in the world does it right.

I must have been thinking of observeValueForKeyPath:ofObject:change:context:, where typically you check the given key path against various possible values and fall through to super if it doesn't match any of them.

In any case, I more often use the keyPathsForValuesAffecting<Key> approach anyway.

[UPDATE: Thanks to Christiaan Hofman for pointing out that my description of observeValueForKeyPath:ofObject:change:context: is also Doing It Wrong. So never mind that and pretend I wrote this instead.]

2 thoughts on “keyPathsForValuesAffectingValueForKey: — doing it wrong

  1. Just noticed in the above post that if I use greater than or less than signs, that text is left out of my comments. Which makes the comment make no sense at all. Let me try again:

    In any case, I more often use the keyPathsForValuesAffecting<Key> approach anyway.

    But doesn't the same requirement hold there: that you need to call [super keyPathsForValuesAffecting<Key>] to make sure that the superclasses wishes aren't overridden?

  2. Setting a new personal record for a belated reply:

    Greg, I think you're right. I was just looking at some code I wrote a year or two ago, and wondering why I didn't do what you point out should be done. I remembered this post I wrote (and had been corrected on), came here to refresh my memory, and saw your comment. No idea why I didn't respond at the time or whether you'll be notified of this reply.

    Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.