1.14 Key-Value Coding
Objective-C lets you call methods
specified by variables at runtime using the selector mechanism.
Key-value coding is a library facility that puts field access on the
same dynamic footing: you can access an object's
fields by naming them. For example, you could use the following code
to retrieve the parent field of a window object:
Window* parentWind = [wind valueForKey:@"parent"];
Because you can pass a string variable to
-valueForKey: as well as a literal value, this is
another way your program's behavior can vary based
on values that aren't known until runtime.
NSObject implements
-valueForKey: method as part of the
NSKeyValueCoding category, which declares methods for
reading from and writing to the fields of objects. These methods
store and retrieve Objective-C objects, so their primary use is in
accessing objects. However, even if your fields are integers or other
numeric types, you can still use key-value coding to retrieve and set
them. The methods will take NSNumber objects and
automatically convert them to set numeric fields, and return
NSNumber objects when you read numeric fields.
1.14.1 Access Permissions
The key-value methods can bypass the access
modifiers of the static language: you can read and write to
private fields as
easily as to public ones. This might seem like a violation of the
object's declared interface. However, you can
prevent key-value methods from bypassing your access modifiers by
overriding
+accessInstanceVariablesDirectly
to return NO.
In addition, the key-value methods first search for an appropriate
accessor method in your class before attempting to read from or write
to a field directly. For example, the methods that read a field named
field will look for accessor methods with the
following names (the order will vary as described in the next
section):
getField
field
_getField
_field
The key-value methods will take care of uppercasing the first letter
of the field name before prepending get or
set.
 |
Although the key-value methods will search for methods or fields
whose names start with an underscore, Apple has reserved these names
for its internal use. Your classes should not have methods or fields
that start with an underscore.
|
|
If your class provides accessor methods with the appropriate names,
they will be called even if they are private methods not declared in
your class's interface.
1.14.2 NSKeyValueCoding Methods
The NSKeyValueCoding protocol declares (and
NSObject implements) six methods that let your
objects use key-value coding:
-(id )valueForKey:(NSString*)key
-
Given the name of
a field, returns the value stored in that field. If
key is "field",
-valueForKey: tries the following ways to get the
associated value:
Calls -getField, if it exists.
Calls -field, if it exists.
Calls -_getField, if it exists.
Calls -_field, if it exists.
Reads field, if it exists and direct access is
allowed.
Reads _field, if it exists and direct access is
allowed.
If all of these fail, -valueForKey: calls
-handleQueryWithUnboundKey: on your object.
-(void )takeValue:(id )value
forKey:(NSString*)key
-
Given the
(pointer to the) object, this method stores the pointer to the object
in the field of the receiver named by the key. If
key is "field",
-takeValue:forKey: tries the following ways to set
the associated value:
Calls -setField:, if it exists.
Calls -_setField:, if it exists.
Sets field, if it exists and direct access is
allowed.
Sets _field, if it exists and direct access is
allowed.
If all of these fail, -takeValue:forKey: calls
-handleTakeValue:forUnboundKey: on your instance.
- (id )storedValueForKey:(NSString*)key
-
Works like
-valueForKey:, but with a possibly different
search sequence:
If +useStoredAccessor returns
NO, the sequence is the same as with
-valueForKey:.
If +useStoredAccessor returns
YES (the default behavior), this method starts
searching in reserved accessors (ones starting with underscores)
first.
For example, if key is
"field", and +useStoredAccessor
returns YES,
-storedValueForKey: tries the following ways to
get the associated value:
Calls -_getField, if it exists.
Calls -_field, if it exists.
Reads _field, if it exists and direct access is
allowed.
Reads field, if it exists and direct access is
allowed.
Calls -getField, if it exists.
Calls -field, if it exists.
If all of these fail, -storedValueForKey: calls
-handleQueryWithUnboundKey: on your instance.
The alternative search sequence supported by
-storedValueForKey: facilitates using key-value
coding for storing and retrieving objects from a database, when you
want to bypass public accessors that may have side-effects.
-(void )takeStoredValue:(id )value
forKey:(NSString*)key
-
Works like
-takeValue:forKey:, but with a possibly different
search sequence:
If -useStoredAccessor return
NO, the sequence is the same.
If +useStoredAccessor returns
YES (the default behavior), this method starts
searching in reserved accessors (ones starting with underscore)
first.
For example, if the key is field, and
+useStoredAccessor returns
YES,
-takeStoredValue:forKey: tries the following ways
to get the associated value:
Calls -_setField:, if it exists.
Sets _field, if it exists and direct access is
allowed.
Sets field, if it exists and direct access is
allowed.
Calls -setField:, if it exists.
If all of these fail, -takeStoredValue:forKey:
calls -handleTakeValue:forUnboundKey: on your
object.
+(BOOL)accessInstanceVariablesDirectly
-
The NSObject version
returns YES. Override this in your class to
affect the search sequence for the basic methods
-valueForKey: and
-takeValueForKey:.
+(BOOL)useStoredAccessor
-
The
NSObject version returns
YES. Override this in your class to affect the
search sequence for the stored methods
-storedValueForKey: and
-takeStoredValue:forKey:.
1.14.3 Handling Key Lookup Failures
The category
NSKeyValueCodingExceptions provides three methods for handling
failures in the lookup sequence and other problems:
-(id )handleQueryWithUnboundKey:(NSString*)key
-
Called when lookup fails for a getter
(-valueForKey: or
-storedValueForKey:) with the provided key. The
default version of this method, provided in
NSObject, raises an
UnknownKeyException. Override this to handle things your
way.
-(void )handleTakeValue:(id )value
forUnboundKey:(NSString*)key
-
Called when lookup fails for a setter
(-takeValueForKey: or
-takeStoredValueForKey:) with the provided key.
The default version of this method, provided in
NSObject, raises an
UnknownKeyException. Override this to handle
things your way.
-(void )unableToSetNilForKey:(NSString*)key
-
Called
when you pass nil in to a setter for a numeric
field. NSObject's version raises
an exception. Override this in your class if there is a plausible
numeric value (zero, or an out-of-band value) to use.
|