Skip to content

Instantly share code, notes, and snippets.

@NavidMitchell
Created December 17, 2013 17:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NavidMitchell/8009299 to your computer and use it in GitHub Desktop.
Save NavidMitchell/8009299 to your computer and use it in GitHub Desktop.
Json to Objective-c un-marshaller
//
// THXDictionaryMapper.m
// Spark
//
// Created by Navid Mitchell on 6/19/13.
// Copyright (c) 2013 Navid Mitchell. All rights reserved.
//
#import "THXDictionaryMapper.h"
#import "objc/runtime.h"
#import "THXSparkDateFormatter.h"
@implementation THXDictionaryMapper
@synthesize propertyReplacement = _propertyReplacement;
-(NSDictionary *)convertObject:(id)object{
NSMutableDictionary *results = [[NSMutableDictionary alloc] init];
NSArray *properties = [self getPropertyNames:[object class]];
for (NSString *propertyName in properties) {
id value = [object valueForKey:propertyName];
value = [self convertValue:value];
if(value == nil){
value = [[NSNull alloc]init];
}
[results setObject:value forKey:[self convertName:propertyName]];
}
return results;
}
-(NSArray *)convertArray:(NSArray *)array{
NSMutableArray *ret = [[NSMutableArray alloc]init];
for (id i in array){
[ret addObject:[self convertValue:i]];
}
return ret;
}
-(id)convertValue:(id)value{
if([self shouldExpand:value]){
value = [self convertObject:value];
}else if([value isKindOfClass:[NSArray class]]){
value = [self convertArray:value];
} else if ([value isKindOfClass:[NSDate class]]) {
value = [self stringFromDate:value];
}
return value;
}
-(NSString*)convertName:(NSString *)name{
NSString *ret = name;
if(_propertyReplacement != nil){
ret = [_propertyReplacement objectForKey:name];
if(ret == nil){
ret = name;
}
}
return ret;
}
-(Boolean)shouldExpand:(id)object{
Boolean ret = NO;
if(object != nil
&& ![object isKindOfClass:[NSArray class]]
&& ![object isKindOfClass:[NSDate class]]
&& ![object isKindOfClass:[NSNumber class]]
&& ![object isKindOfClass:[NSString class]]){
ret = YES;
}
return ret;
}
/**
* Returns all property names for the given class and its superclasses.
*/
-(NSArray *)getPropertyNames:(Class)clazz{
NSMutableArray *ret = [[NSMutableArray alloc]init];
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(clazz, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
const char *propName = property_getName(property);
if(propName) {
//** Not used now but if we wanted a type as well this could be used
// const char *propType = getPropertyType(property);
// NSString *propertyType = [NSString stringWithUTF8String:propType];
NSString *propertyName = [NSString stringWithUTF8String:propName];
[ret addObject:propertyName];
}
}
free(properties);
clazz = class_getSuperclass(clazz);
if(clazz != nil){
NSString *className = [NSString stringWithUTF8String:class_getName(clazz)];
if(![className isEqualToString:@"NSObject"]){
[ret addObjectsFromArray:[self getPropertyNames:clazz]];
}
}
return ret;
}
-(NSString *)stringFromDate:(NSDate *)date{
THXSparkDateFormatter *formatter = [[THXSparkDateFormatter alloc]init];
return [formatter stringFromDate:date];
}
//*** Currently not used. Left here for ref in case we want to cache "Mapping Paths"
static const char * getPropertyType(objc_property_t property) {
const char *attributes = property_getAttributes(property);
printf("attributes=%s\n", attributes);
char buffer[1 + strlen(attributes)];
strcpy(buffer, attributes);
char *state = buffer, *attribute;
while ((attribute = strsep(&state, ",")) != NULL) {
if (attribute[0] == 'T' && attribute[1] != '@') {
// it's a C primitive type:
/*
if you want a list of what will be returned for these primitives, search online for
"objective-c" "Property Attribute Description Examples"
apple docs list plenty of examples of what you get for int "i", long "l", unsigned "I", struct, etc.
*/
return (const char *)[[NSData dataWithBytes:(attribute + 1) length:strlen(attribute) - 1] bytes];
}
else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
// it's an ObjC id type:
return "id";
}
else if (attribute[0] == 'T' && attribute[1] == '@') {
// it's another ObjC object type:
return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
}
}
return "";
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment