0

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?

ray
  • 1,966
  • 4
  • 24
  • 39
  • Ignoring some other confusion up there, I suspect the question you are asking relates to the naming convention of automatically synthesized properties. Which appends an `_` to the property name, so `@property aString`, is accessed via `_aString` if automatically synthesized. – Cooper Buckingham Jul 07 '14 at 20:43
  • Yeah, but your also looking at a selector that is a string object. So that's part of your confusion. – Cooper Buckingham Jul 07 '14 at 20:50

1 Answers1

5
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)])
...
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Strictly speaking the code is incorrect. You are checking for the getter, then set the variable. You should ask for the setter, which would be "set" followed by the uppercased variable name followed by a colon. – Gerd K Jul 08 '14 at 02:28
  • @GerdK: You are completely right and I have updated the answer accordingly. Thanks for the feedback! – Martin R Jul 08 '14 at 05:34