Mapping NSDictionary to NSObject subclass

1.9k views Asked by At

I'm working on cline-server app. I'm getting JSON objects as response from the server, then I'm converting JSON to NSDictionary. Now I need to map NSDictionary to custom data object. So I have created BasicDataObject class that has:

#pragma mark - Inits

- (id)initWithDictionary:(NSDictionary *)dictionary {
    self = [super init];

    if (self) {
        [self setValuesForKeysWithDictionary:dictionary];
    }

    return self;
}

#pragma mark - Service

- (id)valueForUndefinedKey:(NSString *)key {
    NSArray *allKeys = [self allKeys];
    id returnObject = nil;
    BOOL keyFound = NO;

    for (NSString *propertyName in allKeys) {
        if ([propertyName isEqualToString:key]) {
            id object = [self performSelector:NSSelectorFromString(key)];

            returnObject = object ? object : [NSNull null];
            keyFound = YES;
            break;
        }
    }

    if (!keyFound) {
        @throw [NSException exceptionWithName:NSUndefinedKeyException reason:[NSString stringWithFormat:@"key '%@' not found", key] userInfo:nil];
    }

    return returnObject;
}

- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
    NSString *capitalizedString = [key stringByReplacingCharactersInRange:NSMakeRange(0,1)
                                                               withString:[[key substringToIndex:1] capitalizedString]];
    NSString *setterString = [NSString stringWithFormat:@"set%@:", capitalizedString];

    [self performSelector:NSSelectorFromString(setterString) withObject:value];
}

- (void)setNilValueForKey:(NSString *)key {
    object_setInstanceVariable(self, key.UTF8String, 0);
}

- (NSArray *)allKeys {
    unsigned int propertyCount = 0;
    objc_property_t *properties = class_copyPropertyList(self.class, &propertyCount);
    NSMutableArray *propertyNames = [NSMutableArray array];

    for (unsigned int i = 0; i < propertyCount; ++i) {
        objc_property_t property = properties[i];
        const char *name = property_getName(property);

        [propertyNames addObject:[NSString stringWithUTF8String:name]];
    }

    free(properties);

    return propertyNames;
}

Each data object is a subclass of this class, so it could be initialised from NSDictionary. If some data object subclass needs some custom initialisation, I'm overriding it's:

- (id)initWithDictionary:(NSDictionary *)dictionary

Is it correct/good approach, or do I need to add something more?

1

There are 1 answers

0
atomkirk On BEST ANSWER

This is an OK way to do this. Ive found that rarely are the json keys the most appropriate names for my object's properties, so most people's code that I've seen manually sets each property on their object so they can 1) name it whatever they want 2) convert to primitive values from the json dictionary, which will always contain objects. (Eg NSNumber -> float)