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.
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.
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
:.
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.
18.217.147.193