This article describes the basic principles of key-value coding.
Keys and Key Paths
Getting Attribute Values Using Key-Value Coding
Setting Attribute Values Using Key-Value Coding
Dot Syntax and Key-Value Coding
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.
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
; however 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.
Note: Collection objects, such as NSArray
, NSSet
, and NSDictionary
, can’t contain nil
as a value. Instead, nil
values are represented by a special object, NSNull
. NSNull
provides a single instance that represents the nil
value for object properties. The default implementations of dictionaryWithValuesForKeys:
and setValuesForKeysWithDictionary:
translates between NSNull
and nil
automatically, so your objects don’t have to explicitly test for NSNull values.
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.
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.
Objective-C 2.0’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. It is important to 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:[NSNumber numberWithInt: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:[NSNumber numberWithInt:2] |
forKeyPath:@"linkedInstance.integerProperty"]; |
© 2003, 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-02-04)