KVC Collection Operators
Rubyists laugh at Objective-C’s bloated syntax.
Although we lost a few pounds over the summer with our sleek new object literals, those Red-headed bullies still taunt us with their map one-liners and their fancy Symbol#to_proc.
Really, a lot of how elegant (or clever) a language is comes down to how well it avoids loops. for, while; even fast enumeration expressions are a drag. No matter how you sugar-coat them, loops will be a block of code that does something that is much simpler to describe in natural language.
“get me the average salary of all of the employees in this array”, versus…
double totalMeh.
Fortunately, Key-Value Coding gives us a much more concise–almost Ruby-like–way to do this:
[employees valueKVC Collection Operators allows actions to be performed on a collection using key path notation in value. Any time you see @ in a key path, it denotes a particular aggregate function whose result can be returned or chained, just like any other key path.
Collection Operators fall into one of three different categories, according to the kind of value they return:
- Simple Collection Operators return strings, numbers, or dates, depending on the operator.
- Object Operators return an array.
- Array and Set Operators return an array or set, depending on the operator.
The best way to understand how these work is to see them in action. Consider a Product class, and a products array with the following data:
@interface Product : NSObject
@property NSString *name;
@property double price;
@property NSDate *launchedKey-Value Coding automatically boxes and un-boxes scalars into
NSNumberorNSValueas necessary to make everything work.
| Name | Price | Launch Date | 
|---|---|---|
| iPhone 5 | $199 | September 21, 2012 | 
| iPad Mini | $329 | November 2, 2012 | 
| MacBook Pro | $1699 | June 11, 2012 | 
| iMac | $1299 | November 2, 2012 | 
Simple Collection Operators
- 
            @count: Returns the number of objects in the collection as anNSNumber.
- 
            @sum: Converts each object in the collection to adouble, computes the sum, and returns the sum as anNSNumber.
- 
            @avg: Takes thedoublevalue of each object in the collection, and returns the average value as anNSNumber.
- 
            @max: Determines the maximum value usingcompare:. Objects must support comparison with one another for this to work.
- 
            @min: Same as@max, but returns the minimum value in the collection.
Example:
[products valueObject Operators
Let’s say we have an inventory array, representing the current stock of our local Apple store (which is running low on iPad Mini, and doesn’t have the new iMac, which hasn’t shipped yet):
NSArray *inventory = @[i- 
      @union/Of Objects @distinct: Returns an array of the objects in the property specified in the key path to the right of the operator.Union Of Objects @distinctremoves duplicates, whereasUnion Of Objects @uniondoes not.Of Objects 
Example:
[inventory valueArray and Set Operators
Array and Set Operators are similar to Object Operators, but they work on collections of NSArray and NSSet.
This would be useful if we were to, for example, compare the inventory of several stores, say apple, (same as in the previous example) and verizon (which sells iPhone 5 and iPad Mini, and has both in stock).
- 
    @distinct/Union Of Arrays @union: Returns an array containing the combined values of each array in the collection, as specified by the key path to the right of the operator. As you’d expect, theOf Arrays distinctversion removes duplicate values.
- 
  @distinct: Similar toUnion Of Sets @distinct, but it expects anUnion Of Arrays NSSetcontainingNSSetobjects, and returns anNSSet. Because sets can’t contain duplicate values anyway, there is only thedistinctoperator.
Example:
[@[appleThis is Probably a Terrible Idea
Curiously, Apple’s documentation on KVC collection operators goes out of its way to make the following point:
Note: It is not currently possible to define your own collection operators.
This makes sense to spell out, since that’s what most people are thinking about once they see collection operators for the first time.
However, as it turns out, it is actually possible, with a little help from our friend, objc/runtime.
Guy English has a pretty amazing post wherein he swizzles value to parse a custom-defined DSL, which extends the existing offerings to interesting effect:
NSArray *names = [allThis code would get the names of anyone who has taken fewer than 10 days off (to remind them to take a vacation, no doubt!).
Or, taken to a ridiculous extreme:
NSArray *albumEat your heart out, Ruby. This one-liner filters a record collection for artists whose name matches “Bon Iver”, and initializes an NSImage from the album cover image data of the matching albums.
Is this a good idea? Probably not. (NSPredicate is rad, and breaking complicated logic up is under-rated)
Is this insanely cool? You bet! This clever example has shown a possible direction for future Objective-C DSLs and meta-programming.
KVC Collection Operators are a must-know for anyone who wants to save a few extra lines of code and look cool in the process.
While scripting languages like Ruby boast considerably more flexibility in its one-liner capability, perhaps we should take a moment to celebrate the restraint built into Objective-C and Collection Operators. After all, Ruby is hella slow, amiright? </troll>