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.
Why do we keep instance variables private? We don't want other classes to depend on them. Moreover it gives the flexibility to change a variable's type or implementation on a whim or an impulse.
Do the setter/getter methods always affect only values in objects where they are declared, even called from a subclass by inheritance? You cannot inherit the methods but not the variables. You inherit everything from the parent class. Private just means that you cannot directly access it, but it is still there.
In swift to override inherited properties or methods in subclass we use override keyword which will tells the compiler to check the overriding method or property definition matches with the base class or not.
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);
}
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];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With