Search code examples
objective-cios7key-value-coding

Key-Value coding with auto-synthesized properties on NSObject subclass: respondsToSelector returns NO for all property accessors?


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?


Solution

  • 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)])
    ...