If you're not familiar with the term, this just means instances where you're using strings and a certain convention to identify methods that can be called on a given object. A particularly common instance of this is key-value observing such as
-[NSObject addObserver:forKeyPath:options:context:], where you want to pass a key that you know is going to be valid and not return a runtime error.
A post got some attention recently promoting a way to statically-check key-value-coding methods. I've been using something along those lines for a while, but it has some important differences.
The disadvantage to the
NSStringFromSelector() approach is that it doesn't work in cases like
hidden where the getter is called
isHidden, since there is no valid selector called
hidden. It also does not specify on which object the selector must be defined, so you could get away with mentioning a selector that is bogus for that object, but happens to be defined somewhere else (triggering a runtime error at some unknown time in the future).
My macro (which does support this usage) is as follows:
//o is an object type, k is the key on which to check validity //returns a NSString constant of the relevant key #define KVC(o, k) (0 && sizeof(o.k) ? @#k : @#k) //Usage: ObjectWithMethodCalledKeyName *object = ...; [object addObserver:self forKeyPath:KVC(object, keyName) options:0 context:NULL];
Let's dissect briefly when this will work and when it doesn't. It uses the fact that you can do
object.foo to call whatever the getter is for
object or just the method named
foo if there is no property called
foo. All great so far, but we don't actually want to call this method, just find out statically whether it would be valid to call the method on an object of the type of
So, I use
sizeof() as a way to invoke the compiler to consider the expression statically. Then, since I want it to return the key regardless of the actual result of
sizeof(), avoid it being considered by a short-circuiting boolean operation and a ternary operator. The
# stringifies k and the
@ makes it an
Also available in gist!