Key-Value Coding Fundamentals

This article describes the basic principles of key-value coding.

Keys and Key Paths

A key is a string that identifies a specific property of an object. Typically, a key corresponds to the name of an accessor method or instance variable in the receiving object. Keys must use ASCII encoding, begin with a lowercase letter, and may not contain whitespace.

Some example keys would be payee, openingBalance, transactions and amount.

A key path is a string of dot separated keys that is used to specify a sequence of object properties to traverse. The property of the first key in the sequence is relative to the receiver, and each subsequent key is evaluated relative to the value of the previous property.

For example, the key path address.street would get the value of the address property from the receiving object, and then determine the street property relative to the address object.

Getting Attribute Values Using Key-Value Coding

The method valueForKey: returns the value for the specified key, relative to the receiver. If there is no accessor or instance variable for the specified key, then the receiver sends itself a valueForUndefinedKey: message. The default implementation of valueForUndefinedKey: raises an NSUndefinedKeyException; subclasses can override this behavior.

Similarly, valueForKeyPath: returns the value for the specified key path, relative to the receiver. Any object in the key path sequence that is not key-value coding compliant for the appropriate key receives a valueForUndefinedKey: message.

The method dictionaryWithValuesForKeys: retrieves the values for an array of keys relative to the receiver. The returned NSDictionary contains values for all the keys in the array.

When a value is returned for a key path that contains a key for a to-many property, and that key is not the last key in the path, the returned value is a collection containing all the values for the keys to the right of the to-many key. For example, requesting the value of the key path transactions.payee returns an array containing all the payee objects, for all the transactions. This also works for multiple arrays in the key path. The key path accounts.transactions.payee would return an array with all the payee objects, for all the transactions, in all the accounts.

Setting Attribute Values Using Key-Value Coding

The method setValue:forKey: sets the value of the specified key, relative to the receiver, to the provided value. The default implementation of setValue:forKey: automatically unwraps NSValue objects that represent scalars and structs and assigns them to the property. See “Scalar and Structure Support” for details on the wrapping and unwrapping semantics.

If the specified key does not exist, the receiver is sent a setValue:forUndefinedKey: message. The default implementation of setValue:forUndefinedKey: raises an NSUndefinedKeyException; however, subclasses can override this method to handle the request in a custom manner.

The method setValue:forKeyPath: behaves in a similar fashion, but it is able to handle a key path as well as a single key.

Finally, setValuesForKeysWithDictionary: sets the properties of the receiver with the values in the specified dictionary, using the dictionary keys to identify the properties. The default implementation invokes setValue:forKey: for each key-value pair, substituting nil for NSNull objects as required.

One additional issue that you should consider is what happens when an attempt is made to set a non-object property to a nil value. In this case, the receiver sends itself a setNilValueForKey: message. The default implementation of setNilValueForKey: raises an NSInvalidArgumentException. Your application can override this method to substitute a default value or a marker value, and then invoke setValue:forKey: with the new value.

Dot Syntax and Key-Value Coding

Objective-C’s dot syntax and key-value coding are orthogonal technologies. You can use key-value coding whether or not you use the dot syntax, and you can use the dot syntax whether or not you use KVC. Both, though, make use of a “dot syntax.” In the case of key-value coding, the syntax is used to delimit elements in a key path. Remember that when you access a property using the dot syntax, you invoke the receiver’s standard accessor methods.

You can use key-value coding methods to access a property, for example, given a class defined as follows:

@interface MyClass
@property NSString *stringProperty;
@property NSInteger integerProperty;
@property MyClass *linkedInstance;
@end

you could access the properties in an instance using KVC:

MyClass *myInstance = [[MyClass alloc] init];
NSString *string = [myInstance valueForKey:@"stringProperty"];
[myInstance setValue:@2 forKey:@"integerProperty"];

To illustrate the difference between the properties dot syntax and KVC key paths, consider the following.

MyClass *anotherInstance = [[MyClass alloc] init];
myInstance.linkedInstance = anotherInstance;
myInstance.linkedInstance.integerProperty = 2;

This has the same result as:

MyClass *anotherInstance = [[MyClass alloc] init];
myInstance.linkedInstance = anotherInstance;
[myInstance setValue:@2 forKeyPath:@"linkedInstance.integerProperty"];