ConfusedNoob
ConfusedNoob

Reputation: 10186

How to check at runtime if a property was declared @dynamic

I'm working on a dynamic implementation of a dictionary that also supports properties declared using the @dynamic keyword (similar to NSManagedObject).

Can I tell at runtime if a particular selector was declared with @dynamic? Is this just compiler trickery for design time tooling and lost at runtime or is there someway to inspect this?

+ (BOOL) resolveInstanceMethod:(SEL)sel
{
    NSString *method = NSStringFromSelector(sel);
    // ideally I could also check here if the selector is @dynamic
    if ([method hasPrefix:@"set"] && [method rangeOfString:@":"].location == method.length -1) {
        class_addMethod([self class], sel, (IMP) dynamicSet, "v@:@");
        return YES;
    }
    else if ([method hasPrefix:@"get"] && [method rangeOfString:@":"].location == method.length -1) {
        class_addMethod([self class], sel, (IMP) dynamicGet, "v@:@");
        return YES;
    }

    BOOL value = [super resolveInstanceMethod:sel];
    return value;
}

Also, my class subclasses NSDictionary but it when [super resolveInstanceMethod:sel] is called for an existing method - it still returns false?

Upvotes: 3

Views: 425

Answers (1)

Carl Veazey
Carl Veazey

Reputation: 18363

If you know the name of the property you can use some runtime functions to investigate whether it's a dynamic property or not, as shown in the following function. Make sure to import <objc/runtime.h>.

BOOL isClassPropertyDynamic(Class theClass, NSString *propertyName)
{
    BOOL isDynamic = NO;
    objc_property_t property = class_getProperty(theClass, [propertyName UTF8String]);
    char *dynamicAttributeValue = property_copyAttributeValue(property, "D");
    if (dynamicAttributeValue != NULL) {
        isDynamic = YES;
        free(dynamicAttributeValue);
    }
    return isDynamic;
}

However, it's not always going to be easy to go from a selector name to the property, as both getters and setters names can be customized at declaration time. Typically that is only done for getters of boolean properties but technically anyone can break that convention.

Conventionally, if a selector starts with "set" followed by an uppercase letter and contains one ":" at the end, the property name would be the string resulting from removing "set" and ":" and making the first letter lowercase. If a selector starts with "is" followed by an uppercase letter and has no arguments, then the property name corresponding to that would be the string resulting from removing "is" and making the first letter lowercase. Selectors that have no arguments and don't start with "is" and an uppercase letter would generally have the property name and the selector name the same.

Again, that's just convention and will be broken by somebody somewhere. So, you have to decide if it's truly valuable to determine whether a selector corresponds to a dynamic property or not (like borrrden I doubt it's really relevant but I'm not familiar with your requirement).

You could also follow rob mayoff's excellent suggestion from the comments that you "iterate over all of the properties (using class_copyPropertyList ) and check the G and S (attributes) of each" to build a mapping between selectors and properties.

Upvotes: 3

Related Questions