bgfriend0
bgfriend0

Reputation: 1152

Best way to avoid hardcoded strings in nested KVO keypaths

When registering to observe an object via KVO I write this code to avoid hardcoded strings:

[myObject addObserver:self
           forKeyPath:NSStringFromSelector(@selector(myProperty))
              options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
              context:NULL];

Note the NSStringFromSelector. It protects me at compile-time in the event that I change the name of myProperty and forget I had something observing it.

But the situation is more complicated when using nested properties, e.g., "myProperty1.myProperty2"

My naive solution is to use macros like the following:

#define KEYPATHSTRING1(a) NSStringFromSelector(@selector(a))
#define KEYPATHSTRING2(a, b) [NSString stringWithFormat:@"%@.%@", NSStringFromSelector(@selector(a)), NSStringFromSelector(@selector(b))]
#define KEYPATHSTRING3(a, b, c) [NSString stringWithFormat:@"%@.%@.%@", NSStringFromSelector(@selector(a)), NSStringFromSelector(@selector(b)), NSStringFromSelector(@selector(c))]

Any better or standardized solutions out there? Searches on Google and SO turned up nothing for me that addressed this particular question.

Upvotes: 4

Views: 500

Answers (3)

pkamb
pkamb

Reputation: 35022

Swift 3 adds #keyPath() to generate a key path string from a "property chain".

let keyPathString = #keyPath(MyType.myProperty1.myProperty2)

The tokens inside the function are not Strings and will be checked by the compiler.

Upvotes: 0

Wain
Wain

Reputation: 119031

I haven't tried this (or even compiling it), but you could look at using a variadic helper method:

+ (NSString *)keyPathFromSelectors:(SEL)firstArg, ...
{
    NSMutableArray *keys = [NSMutableArray array];

    va_list args;
    va_start(args, firstArg);

    for (SEL arg = firstArg; arg != nil; arg = va_arg(args, SEL))
    {
        [keys addObject:NSStringFromSelector(arg)];
    }

    va_end(args);

    return [keys componentsJoinedByString:@"."];
}

Upvotes: 2

Vitaly
Vitaly

Reputation: 515

I use EXTKeyPathCoding.h from libextobjc. You can check how they do same at https://github.com/jspahrsummers/libextobjc/blob/master/extobjc/EXTKeyPathCoding.h

Upvotes: 1

Related Questions