Reputation: 17586
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.
Upvotes: 5
Views: 1173
Reputation: 2746
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);
}
Upvotes: 6
Reputation: 15376
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];
}
Upvotes: 2