反射setter方法不起作用

时间:2012-10-10 06:12:42

标签: objective-c reflection

我需要使用反射来调用setter。要做到这一点,我需要选择器。但是我的代码中的setterName var为nil。我班上有安装和吸气。这是我的代码

objc_property_t *allProperties = class_copyPropertyList([object class], &allPropertyCount);
objc_property_t prop = class_getProperty(cls, propName);
for (unsigned int i = 0; i < allPropertyCount; i++) {

    prop = allProperties[i];

}

char *setterName = property_copyAttributeValue(prop, "S");


SEL selector = NSSelectorFromString(setterName);
if([object respondsToSelector:@selector(selector)]){
    return selector;
}
return nil;

2 个答案:

答案 0 :(得分:3)

仅当属性分别定义自定义setter或getter时,才会设置“S”和“G”属性。您的代码需要检查setterName是否为NULL,如果是,则从属性名称生成setter名称。

答案 1 :(得分:3)

回复有点迟,希望这对某人有用!

我启用了ARC,我正在使用生成的getter / setter。

//  NSObject+Properties.m
#import "NSObject+Properties.h"
#import "objc/runtime.h"

@implementation NSObject (Properties)

static const char * getPropertyType(objc_property_t property) {

    //Borrowed from http://stackoverflow.com/questions/754824/get-an-object-attributes-list-in-objective-c
    //Many contributors to final solution

    const char *attributes = property_getAttributes(property);
    printf("attributes=%s\n", attributes);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T' && attribute[1] != '@') {
            // it's a C primitive type:
            /*
             if you want a list of what will be returned for these primitives, search online for
             "objective-c" "Property Attribute Description Examples"
             apple docs list plenty of examples of what you get for int "i", long "l", unsigned "I", struct, etc.
             */
            return (const char *)[[NSData dataWithBytes:(attribute + 1) length:strlen(attribute) - 1] bytes];
        }
        else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
            // it's an ObjC id type:
            return "id";
        }
        else if (attribute[0] == 'T' && attribute[1] == '@') {
            // it's another ObjC object type:
            return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
        }
    }
    return "";
}

- (NSDictionary *) getClassProperties
{
    //Borrowed from http://stackoverflow.com/questions/754824/get-an-object-attributes-list-in-objective-c
    //Many contributors to final solution

    if (self == NULL || self == nil) {
        return nil;
    }

    NSMutableDictionary *results = [[NSMutableDictionary alloc] init];

    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 *propName = property_getName(property);
        if(propName) {
            const char *propType = getPropertyType(property);
            NSString *propertyName = [NSString stringWithUTF8String:propName];
            NSString *propertyType = [NSString stringWithUTF8String:propType];
            [results setObject:propertyType forKey:propertyName];
        }
    }
    free(properties);

    // returning a copy here to make sure the dictionary is immutable
    return [NSDictionary dictionaryWithDictionary:results];
}

-(void) setProperty:(NSString *) propertyName value:(id) value {

    SEL selector = [self buildGenericSetterForPropertyName:propertyName];

    if( selector != NULL ) {
        //The class responds to the selector
        NSMethodSignature *aSignature = [[self class] instanceMethodSignatureForSelector:selector];
        NSInvocation *anInvocation = [NSInvocation invocationWithMethodSignature:aSignature];
        [anInvocation setSelector:selector];
        [anInvocation setTarget:self];
        [anInvocation setArgument:&value atIndex:2];
        [anInvocation invoke];
    }
    else {
        //We don't know what the setter is, so directly access the iVar
        Ivar iVar = class_getInstanceVariable([self class],[propertyName UTF8String]);
        object_setIvar(self, iVar,value);
    }    
}

-(SEL) buildGenericSetterForPropertyName:(NSString *) name {
    //Borrowed from https://github.com/AlanQuatermain/aqtoolkit/blob/master/Extensions/NSObject%2BProperties.m
    NSMutableString * str = [NSMutableString stringWithString: @"set"];
    [str appendString: [[name substringToIndex: 1] uppercaseString]];
    if ( [name length] > 1 )
        [str appendString: [name substringFromIndex: 1]];

    //addition - the setter will accept one argument
    [str appendString:@":"];


    if( [[self class] instancesRespondToSelector:NSSelectorFromString(str)]) {
        return NSSelectorFromString(str);
    }
    else {
        return NULL;
    }
}

@end