Key-value coding provides support for scalar values and data structures by automatically wrapping, and unwrapping, those values in NSNumber and NSValue instances.
Representing Data as Objects
Handling nil Values for Non-Object Properties
Wrapping and Unwrapping Scalar Types
Wrapping and Unwrapping Structs
The default implementations of valueForKey: and setValue:forKey: provide support for automatic object wrapping of the non-object data types, both scalars and structs.
Once valueForKey: has determined the specific accessor method or instance variable that is used to supply the value for the specified key, it examines the return type or the data type. If the value to be returned is not an object, an NSNumber or NSValue object is created for that value and returned in its place.
Similarly, setValue:forKey: determines the data type required by the appropriate accessor or instance variable for the specified key. If the data type is not an object, then the value is extracted from the passed object using the appropriate -<type>Value method.
An additional issue arises when setValue:forKey: is invoked with nil passed as the value for a non-object property. There is no generalized action that is appropriate. The receiver is sent a setNilValueForKey: message when nil is passed as the value for a non-object property. The default implementation of setNilValueForKey: raises an NSInvalidArgumentException exception. A subclass can override this method to provide the appropriate implementation specific behavior.
The example code in Listing 1 responds to an attempt to set a personâÂÂs age, a float value, to a nil value by instead setting the age to 0.
Note: For backward binary compatibility, unableToSetNilForKey: is invoked instead of setNilValueForKey: if the receiverâÂÂs class has overridden the NSObject implementation of unableToSetNilForKey:.
Listing 1 Example implementation of setNilValueForKey:
- (void)setNilValueForKey:(NSString *)theKey |
{ |
if ([theKey isEqualToString:@"age"]) { |
[self setValue:[NSNumber numberWithFloat:0.0] forKey:@"age"]; |
} else |
[super setNilValueForKey:theKey]; |
} |
Table 1 lists the scalar types that are wrapped using NSNumber instances.
Table 2 shows the creation and accessor methods use for wrapping the common NSPoint, NSRange, NSRect, and NSSize structs.
Automatic wrapping and unwrapping is not confined to NSPoint, NSRange, NSRect, and NSSize, all structs can be wrapped in an NSValue object. For example, if you have a class like this:
typedef struct { |
float x, y, z; |
} ThreeFloats; |
@interface MyClass |
- (void)setThreeFloats:(ThreeFloats)threeFloats; |
- (ThreeFloats)threeFloats; |
@end |
Sending an instance of MyClass the message valueForKey: with the parameter @"threeFloats" will invoke the MyClass method threeFloats and return the result wrapped in an NSValue. Likewise sending the instance of MyClass a setValue:forKey: message with an NSValue object wrapping a ThreeFloats struct will invoke setThreeFloats: and pass the result of sending the NSValue object a getValue: message.
Note: This mechanism doesn't take reference counting or garbage collection into account, so take care when using with object-pointer-containing structure types.
© 2003, 2009 Apple Inc. All Rights Reserved. (Last updated: 2009-02-04)