It seems that -valueForKey:
and -valueForKeyPath:
work with arbitrary methods, not only with properties. This seems very convenient:
I first stumbled upon it in Interface Builder, and then made some experiments:
// Thing.h
#import <Foundation/Foundation.h>
@interface Thing : NSObject
- (BOOL) alwaysYES;
- (BOOL) alwaysNO;
@end
// Thing.m
#import "Thing.h"
@implementation Thing
- (BOOL) alwaysYES
{
return YES;
}
- (BOOL) alwaysNO
{
return NO;
}
@end
I can call these methods via -valueForKey:
and -valueForKeyPath:
despite the fact that they are normal methods and no properties:
Thing *aThing = [[Thing alloc] init];
id result;
result = [aThing valueForKey:@"alwaysYES"];
NSLog(@"result is: %@", result);
result = [aThing valueForKeyPath:@"alwaysNO"];
NSLog(@"result is: %@", result);
Compiles, runs and gives the correct results. Is this documented anywhere? Can I safely use it? How can i understand it?
Cocoa's key-value coding (KVC) system is older than support for explicit properties (declared with @property
) in Objective-C, so KVC is defined in terms of methods, not properties.
“Default Search Pattern for valueForKey:
” in the Key-Value Coding Programming Guide spells out how valueForKey:
decides what to do. It starts by looking for (amongst other things) a method whose name is exactly the key you passed to valueForKey:
. Here is the full search pattern, quoted from the documentation:
Searches the class of the receiver for an accessor method whose name matches the pattern
get<Key>
,<key>
, oris<Key>
, in that order. If such a method is found it is invoked. If the type of the method's result is an object pointer type the result is simply returned. If the type of the result is one of the scalar types supported byNSNumber
conversion is done and anNSNumber
is returned. Otherwise, conversion is done and anNSValue
is returned. Results of arbitrary types are converted toNSValue
objects, not justNSPoint
,NSRange
,NSRect
, andNSSize
types).Otherwise (no simple accessor method is found), searches the class of the receiver for methods whose names match the patterns
countOf<Key>
andobjectIn<Key>AtIndex:
(corresponding to the primitive methods defined by theNSArray
class) and<key>AtIndexes:
(corresponding to theNSArray
methodobjectsAtIndexes:
). If thecountOf<Key>
method and at least one of the other two possible methods are found, a collection proxy object that responds to allNSArray
methods is returned. EachNSArray
message sent to the collection proxy object will result in some combination ofcountOf<Key>
,objectIn<Key>AtIndex:
, and<key>AtIndexes:
messages being sent to the original receiver ofvalueForKey:
. If the class of the receiver also implements an optional method whose name matches the patternget<Key>:range:
that method will be used when appropriate for best performance.Otherwise (no simple accessor method or set of array access methods is found), searches the class of the receiver for a threesome of methods whose names match the patterns
countOf<Key>
,enumeratorOf<Key>
, andmemberOf<Key>:
(corresponding to the primitive methods defined by theNSSet
class). If all three methods are found, a collection proxy object that responds to allNSSet
methods is returned. EachNSSet
message sent to the collection proxy object will result in some combination ofcountOf<Key>
,enumeratorOf<Key>
, andmemberOf<Key>:
messages being sent to the original receiver ofvalueForKey:
.Otherwise (no simple accessor method or set of collection access methods is found), if the receiver's class method
accessInstanceVariablesDirectly
returnsYES
, the class of the receiver is searched for an instance variable whose name matches the pattern_<key>
,_is<Key>
,<key>
, oris<Key>
, in that order. If such an instance variable is found, the value of the instance variable in the receiver is returned. If the type of the result is one of the scalar types supported byNSNumber
conversion is done and anNSNumber
is returned. Otherwise, conversion is done and anNSValue
is returned. Results of arbitrary types are converted toNSValue
objects, not justNSPoint
,NSRange
,NSRect
, andNSSize
types.If none of the above situations occurs, returns a result the default implementation invokes
valueForUndefinedKey:
.