Hussain Mansoor
Hussain Mansoor

Reputation: 3124

Set Default values of NSString properties automatically

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

Answers (2)

mak
mak

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

lead_the_zeppelin
lead_the_zeppelin

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

Related Questions