Question

I want to override the setter and getter and find the class of an objc_property_t without doing it individually for each property.

I get all the properties like so:

unsigned int numberOfProperties;
    objc_property_t *propertyArray = class_copyPropertyList([self class], &numberOfProperties);
    for (NSUInteger i = 0; i < numberOfProperties; i++) {
        objc_property_t property = propertyArray[i];
        NSString *name = [[NSString alloc] initWithUTF8String:property_getName(property)];

        property.getter = SEL; //?
    }

This is an example of how I want to override the getter and setter - if there is a better way, let me know. NSInvocation maybe?

- (UIImage *)backgroundImage
{
    return [self overrideGetterWithSelector:NSStringFromSelector(_cmd)];
}

- (void)setBackgroundImage:(UIImage *)backgroundImage
{
    [self overrideSetterForObject:backgroundImage forSelector:NSStringFromSelector(_cmd)];
}

Or is there a way to intercept all messages sent to a class?

My goal is to make a generic way to store properties of a class between launches. You probably want to ask why I don't use NSUserDefaults or NSKeyedArchiver. Well, I am using NSKeyedArchiver - I don't want to manually override every single setter and getter.

Was it helpful?

Solution

You can just use class_replaceMethod from the objc runtime to replace the implementation of the getter.

Example:

- (void)replaceGetters {
    unsigned int numberOfProperties;
    objc_property_t *propertyArray = class_copyPropertyList([self class], &numberOfProperties);
    for (NSUInteger i = 0; i < numberOfProperties; i++) {
        objc_property_t property = propertyArray[i];
        const char *attrs = property_getAttributes(property);
        NSString *name = [[NSString alloc] initWithUTF8String:property_getName(property)];

        // property.getter = SEL; //?
        // becomes
        class_replaceMethod([self class], NSSelectorFromString(name), (IMP)myNewGetter, attrs);
    }
}

id myNewGetter(id self, SEL _cmd) {
    // do whatever you want with the variables....

    // you can work out the name of the variable using - NSStringFromSelector(_cmd)
    // or by looking at the attributes of the property with property_getAttributes(property);
    // There's a V_varName in the property attributes
    // and get it's value using - class_getInstanceVariable ()
    //     Ivar ivar = class_getInstanceVariable([SomeClass class], "_myVarName");
    //     return object_getIvar(self, ivar);
}

OTHER TIPS

You can set up KVO on this and save the data on change.

static const void *KVOContext = &KVOContext;

unsigned int numberOfProperties;
objc_property_t *propertyArray = class_copyPropertyList([self class], &numberOfProperties);
for (NSUInteger i = 0; i < numberOfProperties; i++)
{
    objc_property_t property = propertyArray[i];
    NSString *name = [[NSString alloc] initWithUTF8String:property_getName(property)];
    [self addObserver:self forKeyPath:name options:kNilOptions context:KVOContext];
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top