Reputation: 3124
I have many bean/data classes in my code which I'm using to convert to JSON for network communication purposes. The issue is, if there's a NSString
property in my class I want to set its default value to empty string @"" rather than nil. One option I have is this :Setting Default Values For NSString Properties but I have to write code to set properties values, I don't want to do this.
I tried getting all the properties using Objc runtime and did something like this:
unsigned int numberOfProperties = 0;
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 stringWithUTF8String:property_getName(property)];
const char * propAttr = property_getAttributes(property);
NSString *propString = [NSString stringWithUTF8String:propAttr];
NSArray *attrArray = [propString componentsSeparatedByString:@"\""];
if (attrArray.count > 0) {
NSString *propType = [attrArray objectAtIndex:1];
if ([propType containsString:@"NSString"]) {
[self setValue:@"" forKey:name];
}
}
}
free(propertyArray);
This is working like a charm for me. The only issue is I have inherited classes and this code only sets the values for child class, it doesn't sets values of properties in base class. I'm using xcode 6.3.1 & iOS 8.x. Any help is much appreciated. Thanks
Upvotes: 2
Views: 1526
Reputation: 71
You may define a recursive method setDefaultPropValuesForClass:
in your bean/data base class, e.g. Bean
, and invoke it from base class init method. See the implementation below:
@interface Bean : NSObject
// Add your props
// ...
// .....
@end
@implementation Bean
- (instancetype)init {
self = [super init];
if (self) {
[self setDefaultPropValues];
// TODO: All other initializations
}
return self;
}
- (void)setDefaultPropValues {
[self setDefaultPropValuesForClass:self.class];
}
- (void)setDefaultPropValuesForClass:(Class)refClass {
if (![refClass isSubclassOfClass:[Bean class]]) {
return;
}
// First set default property values in super classes
Class baseClass = class_getSuperclass(refClass);
[self setDefaultPropValuesForClass:baseClass];
//
unsigned int numberOfProperties = 0;
objc_property_t *propertyArray = class_copyPropertyList(refClass, &numberOfProperties);
for (NSUInteger i = 0; i < numberOfProperties; i++)
{
objc_property_t property = propertyArray[i];
NSString *name = [NSString stringWithUTF8String:property_getName(property)];
const char * propAttr = property_getAttributes(property);
NSString *propString = [NSString stringWithUTF8String:propAttr];
NSArray *allAttrs = [propString componentsSeparatedByString:@","];
// Check if property is readonly
if (NSNotFound == [allAttrs indexOfObject:@"R"]) {
// Find Property type token
NSArray * attrArray = [propString componentsSeparatedByString:@"\""];
if (attrArray.count > 1) {
Class propType = NSClassFromString([attrArray objectAtIndex:1]);
if ([propType isSubclassOfClass:[NSString class]]) {
[self setValue:@"" forKey:name];
}
}
}
}
free(propertyArray);
}
@end
Upvotes: 1
Reputation: 2052
Can you check if your class is a subclass by
[self class] is SubclassOfClass:
then get copy of property list of base or super class.
objc_property_t *propertyArray = class_copyPropertyList([[self class]superclass], &numberOfProperties);
Upvotes: 0