Objective-C Lesson 13: Key-Value Coding


Accessing ivars is usually done through accessor methods or dot-notation. But as a means of indirection, there is another way—Key-Value Coding, or KVC. This is a means of setting and getting the values by using strings—specifically, NSString, and its corresponding methods, including the very useful stringWithFormat:.

Methods

KVC involves another layer of abstraction, in the form of two specific methods: -valueForKey: and -setValue:forKey:. These methods work as they do for NSDictionary (which, unsurprisingly, is built upon the same principles). The key is an NSString, constructed as a constant or with any one of NSString’s methods. The code is simple:

NSString *name = [myObject valueForKey:@“name”];

The key is in fact the same name as your variable. It follows a specific sequence of steps:

  1. First, it looks for a getter method with the same name. In the above example, it looks for the -name or -isName (for boolean values) methods; if they are found, it invokes that method and returns that result.
  2. If the getter methods are not found, the method looks for an instance variable by that name: name or _name.

This is a very important mechanism: -valueForKey: uses the metadata in the runtime stack to look into your custom objects. This ability is not available in other languages. Speaking of other languages, experienced Java programmers are familiar with the concepts of autoboxing—converting int and other scalar types into corresponding object types, such as Integer and Double. KVC is the only Objective-C construct that supports autoboxing—it automatically converts scalar types to NSNumbers or NSValues. It will also do the opposite if you set one of these types to a scalar value. Note, however, you must still manually “box” a scalar value before using it in the setValue:ForKey: method:

[self setValue:[NSNumber numberWithFloat:249.42] forKey:@“price”];

If price is a float, the value will be automatically unboxed.

Key Paths

You can combine KVC and dot syntax to create a key path. Imagine that we have a store class; we can use the following syntax:

[store setValue:[NSNumber numberWithFloat:2.99] forKeyPath:@“gallonOfMilk.price];

That is the same as

store.gallonOfMilk.price = 2.99;

These key paths can be as deep as you want them to be.

Aggregated Results

NSArray *prices = [store valueForKeyPath:@“merchandise.price”];
// Merchandise is an array

If you ask an NSArray for a value for a key, it will create another array, ask each object for the value specified in the key path, and adds these values to the new array. It basically loops over each value in the array, and sends each object the method valueForKeyPath:@“price”.

Advanced Operators

  • @count:
    count = [store valueForKeyPath:@“merchandise.@count”];

    The @count directive tells the KVC mechanism to get the count of the result of the rest of the key path.

  • @sum:
    totalPrice = [store valueForKeyPath:@“merchandise.@sum.price”];

    The @sum directive gets the sum of all the requested values—in this case, the sum of all the prices of the merchandise.

  • @avg:
    avgPrice = [store valueForKeyPath:@“merchandise.@avg.price];

    The @avg directive gets the average of all the values.

  • @min and @max:
    minPrice = [store valueForKeyPath:@“merchandise.@min.price”];
    maxPrice = [store valueForKeyPath:@“merchandise.@max.price];

    These two are self-explanatory: they return the maximum or minimum of all the values in the range.

  • @distinctUnionOfObjects:
    NSArray *brands = [store valueForKeyPath:@“merchandise.@distinctUnionOfObjects.brand”];

    This key returns a list of individual distinct values—here, it returns a list of all the brands in our hypothetical store.

Note that, unfortunately, you cannot add your own operators.

One More Application

Imagine that you were creating a lottery application (or more likely, a lottery view within another application). You might have 10 views, each with a number, and you highlight each image as a number is drawn. In this case, you’d probably have ten instance variables, maybe named numberView1, numberView2, all the way to numberView10. To light up the views, you could have a large if…else or switch block, comparing the new value to all the values 1–10:

int nextNum = arc4random() % 10 } 1;	// Random number generator, 1–10
    switch (nextNum) {
        case 1:
            // Highlight
            break;
        // etc.
    }

Knowing KVC though, there is a more elegant solution:

[[self valueForKey:[NSString stringWithFormat:@“numberView%d”, nextNum]] highlight];	// Assume highlight method exists and works

Update: That method can be found in this sample project: Click here to download.

About these ads
Leave a comment

7 Comments

  1. Dmitry

     /  June 17, 2012

    Thank you very much!
    It was nice explanation and good example with lottery project! :)
    Good luck!

    Reply
  2. Peter

     /  August 23, 2012

    Why would you “probably have ten instance variables” in your lottery example? Surely you’d just have an array, leading to a much more elegant syntax and much less confusion for anyone not versed in KVC:
    [numberView[nextNum] highlight];

    Reply
  3. DK

     /  January 17, 2013

    In your example above, how would you get an array of items where merchandise.price = a specific value? Let’s say I want all items that cost exactly $3.02… how would I do that using KVC? Thanks.

    Reply
  1. Learn Objective-C in 24 Days « Programming for iOS
  2. Design Patterns: Model-View-Controller « Programming for iOS
  3. Design Patterns: Key-Value Observing « Programming for iOS

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

  • Welcome

    My goal is to make CupsOfCocoa into a beautiful source for beginners to the iPhone platform to get started. Subscribe below for more, and stay tuned!

  • Contact Me

    If you need to contact me for any reason, feel free to send me an email.
  • The Giving Spirit

    If you've found this site helpful, would you consider donating a little sum? Any amount is appreciated...Thanks so much!

  • Roadmap

  • Enter your email address to follow this blog and receive notifications of new posts by email.

    Join 224 other followers

  • Back to the Past

    May 2011
    S M T W T F S
    « Apr   Jun »
    1234567
    891011121314
    15161718192021
    22232425262728
    293031  
  • Time Machine

  • You count!

    • 590,236 views
  • Worldwide Stats

    free counters
Follow

Get every new post delivered to your Inbox.

Join 224 other followers

%d bloggers like this: