JSON

实现一个JSON映射库(2)

字号+ 作者:H5之家 来源:H5之家 2017-04-16 13:04 我要评论( )

解析完成后我们可以得到一个这种的类型: @interface JDCClassProperty : NSObject@property (nonatomic,assign,readonly) objc_property_t property;//c结构property@property (nonatomic,assign,readonly) JDCCla

解析完成后我们可以得到一个这种的类型:

@interface JDCClassProperty : NSObject @property (nonatomic,assign,readonly) objc_property_t property;//c结构property @property (nonatomic,assign,readonly) JDCClassPropertyType propertyType;//property的类型 @property (nonatomic,copy,readonly) NSString *propertyTypeName;//property的类名(比如NSString) @property (nonatomic,copy,readonly) NSString *propertyName;//property的名字(keypath) @property (nonatomic,assign,readonly) BOOL isArray;(用于标记是否为array类型) @property (nonatomic,assign,readonly) BOOL isReadyOnly;(是否为只读类型) - (id)initWithProperty:(objc_property_t)property; @end 映射的实现

拿到了所有property的必要信息以后,需要做的就行把NSDictionary的值复制到我们的Model上面,这是一个递归的过程.

我先用伪代码展示一下主要过程。

id initWithDic(dic){ //遍历当前class的所有property for(property in class.properties){ //如果是自定义类型,则使用自定义类继续序列化,之后使用KVC赋值。 if(property.isCustomType){ Class CustomClass = NSClassFromString(property.typeName); id custom = CustomClass.initWithDic(dic[property.name]); self.setValueForKey(custom,property.name); }else{ self.setValueForKey(dic[property.name],property.name); } } }

在实际实现代码之前我们需要几个模板方法

//通过这个方法来定义keypath->jsonkey的映射 //比如@property (nonatomic,strong)NSString *aid; // @{@"id":"123"}, 我们可以这样实现: //+(NSDictionary *)jdc_jsonSerializationKeyMapper{ // return @{@"aid":@"id"}; //} +(NSDictionary *)jdc_jsonSerializationKeyMapper; //通过这个方法来确定array的item对应的类型,如果property //是NSArray我们需要用这个方法来制定自定义类。例如: //比如@property (nonatomic,strong)NSArray *items; // 我们可以这样实现: // +(NSDictionary *)jdc_KeyPathToClassNameMapper{ // return @{@"items":@"CustomClassName"}; //} +(NSDictionary *)jdc_KeyPathToClassNameMapper;

下面我们来看看实际的映射代码:

- (id)initWithJsonDictionary:(NSDictionary *)jsonDictionary error:(NSError **)error { self = [self init]; NSDictionary *keyPathToJsonKey = [[self class] jdc_jsonSerializationKeyMapper]; NSDictionary *keyPathToClass = [[self class] jdc_KeyPathToClassNameMapper]; NSArray *propertis = [[self class] jdc_classProperties]; for(JDCClassProperty *property in propertis){ //Get json value for mapped keypath id value = [self getJsonValue:property.propertyName jsonKeyPath:keyPathToJsonKey[property.propertyName] dictionary:jsonDictionary]; if (!value) { continue; } switch (property.propertyType) { case JDCClassPropertyStandandJsonType:{ NSString *itemClassName = keyPathToClass[property.propertyName]; if (property.isArray && itemClassName) { Class itemClass = NSClassFromString(itemClassName); NSArray *values = [itemClass modelsFromJsonArray:value error:error]; if (error) { return nil; } [self setValue:values forKey:property.propertyName]; }else{ [self setValue:value forKey:property.propertyName]; } } break; case JDCClassPropertyCustomType:{ Class customClass = NSClassFromString(property.propertyTypeName); id tValue = [[customClass alloc] initWithJsonDictionary:value error:error]; [self setValue:tValue forKey:property.propertyName]; } break; case JDCClassPropertyOtherType:{ @throw [NSException exceptionWithName:@"unsupported json type" reason:@"NSString, NSNumber, NSArray, NSDictionary and custom Class" userInfo:nil]; } break; default:{ [self setValue:value forKey:property.propertyName]; } break; } } return self; } - (id)getJsonValue:(NSString *)keyPath jsonKeyPath:(NSString *)jsonKeyPath dictionary:(NSDictionary *)dicionary { if (jsonKeyPath) { return [dicionary valueForKeyPath:jsonKeyPath]; }else{ return [dicionary valueForKeyPath:keyPath]; } }

到这里JSON map核心代码已经完成了。我们已经实现了一个简单可用的JSON映射框架。另外我还实现了toDictionary功能,思路是差不多的,具体可以参考代码, 完整代码github 。

额外实现NSCoding

NSKeyedArchiver的对象序列化功能平时也会经常用到,但是手写encode和decode方法有点烦,明明都是类似的代码为什么要一直重复的呢。我们可以利用之前的实现的基础用几行代码实现NSKeyedArchiver的encode和decode,我们只需要添加一个NSObject Category即可:

@implementation NSObject (JDCNSCoding) - (instancetype)initWithCoder:(NSCoder *)aDecoder { if (self = [self init]) { NSArray *propertis = [[self class] jdc_classProperties]; for(JDCClassProperty *property in propertis){ if (property.propertyType == JDCClassPropertyOtherType) { @throw [NSException exceptionWithName:@"unsupported json type" reason:@"decoding failed" userInfo:nil]; } id value = [aDecoder decodeObjectForKey:property.propertyName]; [self setValue:value forKey:property.propertyName]; } } return self; } - (void)encodeWithCoder:(NSCoder *)aCoder { NSArray *propertis = [[self class] jdc_classProperties]; for(JDCClassProperty *property in propertis){ if (property.propertyType == JDCClassPropertyOtherType) { @throw [NSException exceptionWithName:@"unsupported json type" reason:@"encoding failed" userInfo:nil]; } id value = [self valueForKey:property.propertyName]; [aCoder encodeObject:value forKey:property.propertyName]; } } @end

需要注意的是这里支持的类型是有限的,具体支持的类型可以参看JDCClassProperty的头文件。

总结

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • JSON教程免费下载

    JSON教程免费下载

    2017-04-16 14:00

  • Json for Java API学习

    Json for Java API学习

    2017-04-16 13:03

  • ajax技术,json,xml,post

    ajax技术,json,xml,post

    2017-04-16 08:06

  • Google Gson的使用方法及JSON 技术对比

    Google Gson的使用方法及JSON 技术对比

    2017-04-16 08:05

网友点评