2013-05-28

Here’s a little experiment I made last week. It’s an alternative syntax for Key-Value Coding, which is, as you may know, one of my favorite features of Objective-C.

My quick hack lets you write stuff like this:

// labels is an array of UILabels
labels.kvc[@"font"] = aNiceFont;

instead of the usual syntax:

[labels setValue:aNiceFont forKey:@"font"];

The idea is to use a Trampoline Object and make use of Keyed Subscripting.

(Keyed Subscripting is the feature that enables C-array-style access to the members of NSArrays and NSDictionaries.)

We’ll first add a method to NSObject to creates and return a trampoline:

@interface KVCTrampoline ()
@property id object;
@end

@implementation NSObject (KVCTrampoline)
- (KVCTrampoline*) kvc
{
    KVCTrampoline * kvc = [KVCTrampoline new];
    kvc.object = self;
    return kvc;
}
@end

The trampoline object implements the methods for Keyed Subscripting, and simply translates them to Key-Value Coding messages to the original receiver:

@implementation KVCTrampoline
- (id)objectForKeyedSubscript:(id)key
{
    return [self.object valueForKeyPath:key];
}
- (void)setObject:(id)obj forKeyedSubscript:(id <NSCopying>)key
{
    [self.object setValue:obj forKeyPath:(NSString*)key];
}
@end

So simple and obvious.

Wait! Why don’t we directly implement Keyed Subscripting on NSObject?

Actually, I have been thinking of mixing KVC and Keyed Subscripting since the latter was unveiled. We could then write:

labels[@"font"] = aNiceFont;

Well, that’s completely feasible but horribly confusing: how do you know that labels is an NSArray, not an NSDictionary? You can’t tell objects from collections anymore, and you probably don’t want that. The whole point of the “kvc” trampoline is to make our intentions clear.

Hopefully.

The code is available as a small repo on gitlab. If you have comments, you can find me on Twitter.