Search code examples
objective-cintrospectiondynamic-typing

How could I check for a particular property at runtime, along with its return type?


Since property named "age" would always have a selector named "age" as well, I could use respondsToSelector as this question suggests and that will tell me if a particular selector exists at runtime in any given object.

If a property named "age" exists, I can verify that. How could I know if that selector (the read method for that property) returns an object (id) or non-object (int)?

Is such type determination possible at runtime, or is the Objective-C way to always assume that someone implemented that method using the type I'm hoping it used, or can I also verify the return type?

This is using the latest Objective-C version (LLVM 4.1) in XCode 4.5.

Update: This is the utility-category-on-NSObject that I came up with:

   - (NSString*) propertyType: (NSString*)propname
{
    objc_property_t aproperty = class_getProperty([self class],  [propname cStringUsingEncoding:NSASCIIStringEncoding] ); // how to get a specific one by name.
    if (aproperty)
    {
     char * property_type_attribute = property_copyAttributeValue(aproperty, "T");
     NSString *result = [NSString stringWithUTF8String:property_type_attribute];
     free(property_type_attribute);
     return result;
    }
    else
        return nil;
}

While looking into this question I also wrote this handy-dandy utility method that can list all the properties on this object:

- (NSArray*) properties;
{
    NSMutableArray *results = [NSMutableArray array];
    @autoreleasepool {

        unsigned int outCount, i;
        objc_property_t *properties = class_copyPropertyList([self class], &outCount);
        for (i = 0; i < outCount; i++) {
            objc_property_t property = properties[i];
            const char * aname=property_getName(property);
            [results addObject:[NSString stringWithUTF8String:aname]];
            //const char * attr= property_getAttributes(property);
            //[results addObject:[NSString stringWithUTF8String:attr]];

        }
        if (properties) {
            free(properties);
        }

  } // end of autorelease pool.
  return results;
}

Solution

  • One approach you can take, assuming you know the property name already, is to use the class_getProperty function. You can also use the property_copyAttributeValue() function to get just a particular attribute by name:

    objc_property_t number_property = class_getProperty([MyClass class], "number");
    char *number_property_type_attribute = property_copyAttributeValue(number_property, "T");
    NSLog(@"number property type attribute = %s", number_property_type_attribute);
    

    Will log:

    2013-01-14 14:45:37.382 RuntimeFun[61304:c07] number property type attribute = i

    Assuming MyClass looks something like:

    @interface MyClass : NSObject
    @property (nonatomic) int number;
    @end
    
    @implementation MyClass
    @end
    

    One you have your type attribute string, you can then compare it to the various Objective-C type encodings. Once you're done with your comparison, be sure to call free() on your attribute string.