Is it possible to define your own key path operators, such as @avg, @sum, etc…
-
2I have to keep fighting the urge to send `cocoa` questions over to the cooking site... – Mark Ransom Nov 04 '10 at 20:17
-
2+1 this is a really fascinating question; one that I've never thought to ask, but one that has revealed some really interesting information. Thanks for asking! – Dave DeLong Nov 04 '10 at 21:13
2 Answers
Short answer: Kinda. You can override valueForKeyPath:
to intercept your custom operator or forward on to super
, but that can be problematic (I'll leave the explanation to that as an exercise to the reader).
Long answer: Yes you can, but it relies on using private behavior (not private api).
After some neat introspection of NSArray
, I found some private methods:
_distinctUnionOfSetsForKeyPath:
_distinctUnionOfObjectsForKeyPath:
_distinctUnionOfArraysForKeyPath:
_unionOfSetsForKeyPath:
_unionOfArraysForKeyPath:
_unionOfObjectsForKeyPath:
_minForKeyPath:
_maxForKeyPath:
_countForKeyPath:
_avgForKeyPath:
_sumForKeyPath:
Well, neat! Those methods seem to match the operators you can use with collections: @sum
, @min
, @max
, @distinctUnionOfObjects
, etc. The @
has been replaced with an underscore and we've got ForKeyPath:
appended.
So it would seem that we can create a new method to match the appropriate signature and we're good to go.
So:
@interface NSArray (CustomOperator)
- (id) _fooForKeyPath:(NSString *)keyPath;
@end
@implementation NSArray (CustomOperator)
- (id) _fooForKeyPath:(NSString *)keyPath {
//keyPath will be what comes after the keyPath. In this example, it will be "self"
return @"Hello world!";
}
@end
NSArray * array = [NSArray arrayWithObjects:@"1", @"2", @"3", nil];
NSLog(@"%@", [array valueForKeyPath:@"@foo.SELF"]); //logs "Hello world!"
It works, but I'm not sure I would rely on this, since it relies on an implementation detail that could change in the future.

- 242,470
- 58
- 448
- 498
-
2Override `-valueForKey:` instead though I would. Read the docs on how NSDictionary implements it. – Mike Abdullah Nov 04 '10 at 21:53
-
1@Mike in the long run it's probably stabler, but the problem with overriding is that these operators are usually only useful on collections, and subclassing collections kinda sucks. :( – Dave DeLong Nov 04 '10 at 21:56
-
1Nice find Dave! However, it does seem a bi brittle as you said. Why do you think that overriding valueForKeyPath: is more dangerous? – cfischer Nov 04 '10 at 22:00
-
1@Fernando: subclassing collections is tricky compared to a category and I haven't played around with it to know what would be involved. Are there specific edge cases you'd have to code for? I don't know. The category approach, though seemingly brittle, just seems simpler to me. – Dave DeLong Nov 04 '10 at 22:10
-
You could also make use of Matt Gallagher's ["Supersequent Implementation"](http://cocoawithlove.com/2008/03/supersequent-implementation.html) technique for categories to basically allow you to just categorize `-valueForKey:` on `NSArray`. Catch your own custom key path operators, and send anything else back up to the "supersequent" implementation. – CIFilter Feb 14 '11 at 05:28
It's possible by overriding valueForKeyPath:
and doing your own custom logic in there, but there's no framework support for it.

- 234,037
- 30
- 302
- 389