I have a simple NSObject
subclass with some properties
@interface MyThing : NSObject
@property (nonatomic, copy) NSString *aString;
//... and so on
@end
But when I try to use key/value coding to set my properties via a dictionary:
+ (instancetype)thingFromDictionary:(NSDictionary *)dict
{
MyThing *newThing = [MyThing new];
for (NSString *key in dict)
{
if ([newThing respondsToSelector:@selector(key)])
{
//do stuff
[newThing setValue:[dict objectForKey:key] forKey:key];
}
else
{
NSLog(@"key %@ doesnt exist. value %@", key, [dict objectForKey:key]);
}
}
return newThing;
}
It turns out that though the dictionary contains keys that match the exact names of my properties, respondsToSelector:
always returns for NO
for those keys. How do I ensure all properties are accessible via the key/value methods?
if ([newThing respondsToSelector:@selector(key)])
checks if the object responds to the the selector "key". The argument of @selector
is a literal key and not expanded.
To create a selector from a string variable, use NSSelectorFromString()
:
if ([newThing respondsToSelector:NSSelectorFromString(key)])
But note, as Gerd K correctly stated in a comment, this checks for the existence of a getter method for the property with that name. To check if the property can bet set
you have to check for the setter method, (e.g. setAString:
):
NSString *key = @"aString";
NSString *setter = [NSString stringWithFormat:@"set%@%@:",
[[key substringToIndex:1] uppercaseString],
[key substringFromIndex:1]];
if ([newThing respondsToSelector:NSSelectorFromString(setter)])
...