5

Objective-C offers runtime reflections feature. I'm trying to find getter/setter selector name of a declared property. I know the basic rule like field/setField:. Anyway I think runtime reflection should offer a feature to resolve the name for complete abstraction, but I couldn't find the function.

How can I resolve the getter/setter method selector (not implementation) of a declared property with runtime reflection in Objective-C (actually Apple's Cocoa)

Or reverse query. (method selector → declared property)

eonil
  • 83,476
  • 81
  • 317
  • 516

2 Answers2

8

I think you can get the selector names only if the property is declared with explicit (setter = XXX and/or getter = XXX)

So to get the getter and setter selector names for some property 'furType' of the class 'Cat':

objc_property_t prop = class_getProperty([Cat class], "furType");

char *setterName = property_copyAttributeValue(prop, "S");
if (setterName == NULL) { /*Assume standard setter*/ }

char *getterName = property_copyAttributeValue(prop, "G");
if (getterName == NULL) { /*Assume standard getter */ }

I don't know of a reverse query, other than iterating through all the properties and looking for matches. Hope that helps.

Firoze Lafeer
  • 17,133
  • 4
  • 54
  • 48
  • 1
    These methods are declared in ``. – rob mayoff Dec 11 '11 at 04:42
  • You must free the returned value string of the method property_copyAttributeValue with free() , as [official document](https://developer.apple.com/documentation/objectivec/1418944-property_copyattributevalue) said. – 0xxxD Jun 29 '18 at 07:53
2

A little update from my NSObject category. Hope this'll help some one:

+(SEL)getterForPropertyWithName:(NSString*)name {
    const char* propertyName = [name cStringUsingEncoding:NSASCIIStringEncoding];
    objc_property_t prop = class_getProperty(self, propertyName);

    const char *selectorName = property_copyAttributeValue(prop, "G");
    if (selectorName == NULL) {
        selectorName = [name cStringUsingEncoding:NSASCIIStringEncoding];
    }
    NSString* selectorString = [NSString stringWithCString:selectorName encoding:NSASCIIStringEncoding];
    return NSSelectorFromString(selectorString);
}

+(SEL)setterForPropertyWithName:(NSString*)name {
    const char* propertyName = [name cStringUsingEncoding:NSASCIIStringEncoding];
    objc_property_t prop = class_getProperty(self, propertyName);

    char *selectorName = property_copyAttributeValue(prop, "S");
    NSString* selectorString;
    if (selectorName == NULL) {
        char firstChar = (char)toupper(propertyName[0]);
        NSString* capitalLetter = [NSString stringWithFormat:@"%c", firstChar];
        NSString* reminder      = [NSString stringWithCString: propertyName+1
                                                     encoding: NSASCIIStringEncoding];
        selectorString = [@[@"set", capitalLetter, reminder, @":"] componentsJoinedByString:@""];
    } else {
        selectorString = [NSString stringWithCString:selectorName encoding:NSASCIIStringEncoding];
    }

    return NSSelectorFromString(selectorString);
}
lazarev
  • 839
  • 10
  • 25
  • Thanks @lazarev for sharing, I put +1. That said, I do not think that the static method is useful in this case. Then, it seems to me that you have to pass a class and not an instance to class_getProperty ([self class], propertyName); – Chrstpsln Jan 16 '19 at 15:44