How to dynamically determine Objective-C property

2019-04-11 00:03发布

问题:

I'm trying to dynamically determine the type of a property in Objective-C. Based on what I have read on this site and elsewhere, I believe I am doing the right thing. However, my code isn't working.

The code snippet below demonstrates the problem. Attempting to get the property information for "backgroundColor" and "frame", both of which are valid properties of UIView, fails (class_getProperty() returns NULL):

id type = [UIView class];        
objc_property_t backgroundColorProperty = class_getProperty(type, "backgroundColor");
fprintf(stdout, "backgroundColorProperty = %d\n", (int)backgroundColorProperty); // prints 0

objc_property_t frameProperty = class_getProperty(type, "frame");
fprintf(stdout, "frameProperty = %d\n", (int)frameProperty); // prints 0

Enumerating the properties as described here doesn't produce the expected results, either. The following code:

NSLog(@"Properties for %@", type);
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(type, &outCount);
for (i = 0; i < outCount; i++) {
    objc_property_t property = properties[i];
    fprintf(stdout, "%s %s\n", property_getName(property), property_getAttributes(property));
}

generates this output:

2012-03-09 13:18:39.108 IOSTest[2921:f803] Properties for UIView
caretRect T{CGRect={CGPoint=ff}{CGSize=ff}},R,N,G_caretRect
gesturesEnabled Tc,N
deliversTouchesForGesturesToSuperview Tc,N
skipsSubviewEnumeration Tc,N
viewTraversalMark Tc,N
viewDelegate T@"UIViewController",N,G_viewDelegate,S_setViewDelegate:
inAnimatedVCTransition Tc,N,GisInAnimatedVCTransition
monitorsSubtree Tc,N,G_monitorsSubtree,S_setMonitorsSubtree:
backgroundColorSystemColorName T@"NSString",&,N,G_backgroundColorSystemColorName,S_setBackgroundColorSystemColorName:
userInteractionEnabled Tc,N,GisUserInteractionEnabled
tag Ti,N,V_tag
layer T@"CALayer",R,N,V_layer

Documented properties such as "backgroundColor", "frame", and others are missing, whereas undocumented properties like "caretRect" and "gesturesEnabled" are included.

Any help would be very much appreciated. In case it is relevant, I'm seeing this behavior on the iOS simulator. I don't know if the same thing would happen on an actual device.

Thanks, Greg

回答1:

You are getting the UIView properties, the problem is backgroundColor is not a UIView property, is a category property. Check UIView.h. I think you can't get a objc_category, but have a look at class-dump.



回答2:

Dodging around the issue slightly, the following works:

NSMethodSignature *signature = [[UIView class] 
            instanceMethodSignatureForSelector:@selector(backgroundColor)];
NSLog(@"%s", [signature methodReturnType]);

So the runtime may somehow have lost the fact that backgroundColor is a property but you seem to start with that information anyway in the first code snippet so it just checks out the return type of the getter.



回答3:

You can find category properties as methods.

@import ObjectiveC;

static void test(Class class, NSString* methodName) {

    Method method = class_getInstanceMethod(class, NSSelectorFromString(methodName));

    const char* type = method_copyReturnType(method);

    printf("%s : %s\n", methodName.UTF8String, type);

    free((void*)type);
}

Then you inspect some...

test([UILabel class], @"alpha");
test([UILabel class], @"textColor");
test([UILabel class], @"isHidden");
test([UILabel class], @"minimumScaleFactor");

After look at these defines in runtime.h

#define _C_ID       '@'
#define _C_CLASS    '#'
#define _C_SEL      ':'
#define _C_CHR      'c'
#define _C_UCHR     'C'
#define _C_SHT      's'
#define _C_USHT     'S'
#define _C_INT      'i'
#define _C_UINT     'I'
...

Don't forget to respect getters/setters notation for BOOL properties, search 'isHidden' instead 'hidden'.