JSONModel是一个解析服务器返回的Json数据的库。
通常服务器传回的json数据要通过写一个数据转换模块将NSDictionary转换为Model,将NSString数据转换为Model中property的数据类型。
JSONModel的出现就是为了将这种解析工作在设计层面完成。
对其源码的核心部分JSONModel.m做了源码阅读,笔记如下:
在
-(id)initWithDictionary:(NSDictionary*)dicterror:(NSError**)err
{
//1、做有效性判断(dict是不是空啊,dict是不是真是一个NSDictionary)
//checkfornilinput
if(!dict){
if(err)*err=[JSONModelErrorerrorInputIsNil];
returnnil;
}
//invalidinput,justcreateemptyinstance
if(![dictisKindOfClass:[NSDictionaryclass]]){
if(err)*err=[JSONModelErrorerrorInvalidData];
//createaclassinstance
self=[superinit];
if(!self){
//superinitdidn'tsucceed
if(err)*err=[JSONModelErrorerrorModelIsInvalid];
//->__restrospectProperties中利用runtimefunction搞出属性列表:
//->获得属性列表class_copyPropertyList(得到objc_property_t数组)->对于每一个objc_property_t调用property_getName获得名称,property_getAttributes获得属性的描述(字符串)->通过解析字符串获得属性的类型、是否是Mutable、是否是基本的JSON类型等等
//->列表保存在classProperties中备用
//doinitialclasssetup,retrospecproperties
[self__setup__];
//看看必传参数中是否在输入参数中都有。
//checkifallrequiredpropertiesarepresent
NSArray*incomingKeysArray=[dictallKeys];
NSSet*incomingKeys=[NSSetsetWithArray:incomingKeysArray];
//getthekeymapper
JSONKeyMapper*keyMapper=keyMappers[__className_];
//transformthekeynames,ifneccessary
if(keyMapper){
//对比dict输入的keyName导入NSSet与keyMapper中JSONKeyMapper对象做keyName的转换。统一转换为对象的propertyname。
NSMutableSet*transformedIncomingKeys=[NSMutableSetsetWithCapacity:requiredProperties.count];
NSString*transformedName=nil;
//loopovertherequiredpropertieslist
//getthemappedkeypath
transformedName=keyMapper.modelToJSONKeyBlock(requiredPropertyName);
//chekifexistsandifso,addtoincomingkeys
if([dictvalueForKeyPath:transformedName]){
[transformedIncomingKeysaddObject:requiredPropertyName];
//overwritetherawincominglistwiththemappedkeynames
incomingKeys=transformedIncomingKeys;
JSONModel(二)
//利用NSSet的isSubsetOfSet:将必传参数表与输入的keyName表对比。如果不是包含关系说明参数传的不够。 //checkformissinginputkeys
if(![requiredPropertiesisSubsetOfSet:incomingKeys]){
//getalistofthemissingproperties
[requiredPropertiesminusSet:incomingKeys];
//notallrequiredpropertiesarein-invalidinput
JMLog(@"Incomingdatawasinvalid[%@initWithDictionary:].Keysmissing:%@",self._className_,requiredProperties);
if(err)*err=[JSONModelErrorerrorInvalidDataWithMissingKeys:requiredProperties]; returnnil;
}
//notneededanymore
incomingKeys=nil;
requiredProperties=nil;
//loopovertheincomingkeysandsetself'sproperties
for(JSONModelClassProperty*propertyin[self__properties__]){
//对于每一个对象的property,通过keyMapper的转换找到对应dictproperty的dictKeyPath,找到值jsonValue。如果没有值,并且这个属性是Optional的就进行下一项property对比。
//convertkeynameotmodelkeys,ifamapperisprovided
NSString*jsonKeyPath=property.name;
if(keyMapper)jsonKeyPath=keyMapper.modelToJSONKeyBlock(property.name);
//JMLog(@"keyPath:%@",jsonKeyPath);
//generalcheckfordatatypecompliance
idjsonValue=[dictvalueForKeyPath:jsonKeyPath];
//checkforOptionalproperties
if(jsonValue==nil&&property.isOptional==YES){
//skipthisproperty,continuewithnextproperty continue;
//对找到的值做类型判断,如果不是JSON应该返回的数据类型就报错。(注意:NSNull是可以作为参数回传的)
ClassjsonValueClass=[jsonValueclass];
BOOLisValueOfAllowedType=NO;
for(ClassallowedTypeinallowedJSONTypes){
if([jsonValueClassisSubclassOfClass:allowedType]){
isValueOfAllowedType=YES;
break;
if(isValueOfAllowedType==NO){
//typenotallowed
JMLog(@"Type%@isnotallowedinJSON.",NSStringFromClass(jsonValueClass));
if(err)*err=[JSONModelErrorerrorInvalidData];
returnnil;
//checkifthere'smatchingpropertyinthemodel
//JSONModelClassProperty*property=classProperties[self.className][key];
//接着对property的属性与jsonValue进行类型匹配:
if(property){
//如果是基本类型(int/float等)直接值拷贝;
//0)handleprimitives
if(property.type==nil&&property.structName==nil){
//justcopythevalue
[selfsetValue:jsonValueforKey:property.name];
//skipdirectlytothenextkey
continue;
//如果是NSNull直接赋空值;
//0.5)handlenils
if(isNull(jsonValue)){
[selfsetValue:nilforKey:property.name];
//如果是值也是一个JsonModel,递归搞JsonModel
//1)checkifpropertyisitselfaJSONModel
if([[property.typeclass]isSubclassOfClass:[JSONModelclass]]){
//initializetheproperty'smodel,storeit
NSError*initError=nil;
idvalue=[[property.typealloc]initWithDictionary:jsonValueerror:&initError];
if(!value){
if(initError&&err)*err=[JSONModelErrorerrorInvalidData];
[selfsetValue:valueforKey:property.name];
//forclarity,doesthesamewithoutcontinue
}else{
//如果property中有protocol解析将jsonValue按照protocol解析,如NSArray<JsonModelSubclass>,protocol就是JsonModelSubclass
//2)checkifthere'saprotocoltotheproperty
//)mightornotbethecasethere'sabuiltintransofrmforit
if(property.protocol){
//JMLog(@"proto:%@",p.protocol);
//->先判断下protocolClass是否在运行环境中存在,如不存在并且property是NSArray类型,直接报错。否则,直接返回。
//->如果protocalClass是JsonModel的子类,
//->如果property.type是NSArray
//->判断一下是否是使用时转换
//->如果为使用时转换则输出一个JSONModelArray(NSArray)的子类
//->如果不是使用时转换则输出一个NSArray,其中的对象全部转换为protocalClass所对应对象
//->如果property.type是NSDictionary
//->将value转换为protocalClass所对应对象
//->根据key存储到一个NSDictionary中输出
jsonValue=[self__transform:jsonValueforProperty:property];
if(!jsonValue){
//如果是基本JSON类型(NSString/NSNumber)
//3.1)handlematchingstandardJSONtypes
if(property.isStandardJSONType&&[jsonValueisKindOfClass:property.type]){
//如果是mutable的,做一份MutableCopy
//mutableproperties
if(property.isMutable){
jsonValue=[jsonValuemutableCopy];
//setthepropertyvalue
[selfsetValue:jsonValueforKey:property.name];
continue;
//如果property.type是NSArray
//3.3)handlevaluestotransform
if(
//如果(类型没有匹配,并且jsonValue不为空)或者是Mutable的property(说明是特殊类型转换)
(![jsonValueisKindOfClass:property.type]&&!isNull(jsonValue))
||
//thepropertyismutable
property.isMutable
){
//利用JSONValueTransformer找到源类型
//searchedaroundthewebhowtodothisbetter
//butdidnotfindanysolution,maybethat'sthebestidea?(hardly)
ClasssourceClass=[JSONValueTransformerclassByResolvingClusterClasses:[jsonValueclass]];
//JMLog(@"totype:[%@]fromtype:[%@]transformer:[%@]",p.type,sourceClass,selectorName);
//buildamethodselectorforthepropertyandjsonobjectclasses
NSString*selectorName=[NSStringstringWithFormat:@"%@From%@:",
(property.structName?property.structName:property.type),//targetname
sourceClass];//sourcename
SELselector=NSSelectorFromString(selectorName);
//checkifthere'satransformerwiththatname
if([valueTransformerrespondsToSelector:selector]){
//it'sOK,believeme...
#pragmaclangdiagnosticpush
#pragmaclangdiagnosticignored"-Warc-performSelector-leaks"
//transformthevalue
jsonValue=[valueTransformerperformSelector:selectorwithObject:jsonValue];
#pragmaclangdiagnosticpop
}else{
//it'snotaJSONdatatype,andthere'snotransformerforit
//ifpropertytypeisnotsupported-that'saprogrammermistaked->exception
@throw[NSExceptionexceptionWithName:@"Typenotallowed"
reason:[NSStringstringWithFormat:@"%@typenotsupportedfor%@.%@",property.type,[selfclass],property.name]
userInfo:nil];
//哪儿都不是的直接存起来
//3.4)handle"allother"cases(ifany)
//最后调用validate:看看结果是不是有效,没问题就返回了。
//runanycustommodelvalidation
NSError*validationError=nil;
BOOLdoesModelDataValidate=[selfvalidate:&validationError];
if(doesModelDataValidate==NO){
if(err)*err=validationError;
//modelisvalid!yay!
returnself;
程序亮点:
1、为了提高效率通过static的NSArray和NSDictionary进行解耦。
2、JSONValueTransformer实现了一个可复用的类型转换模板。
4、NSScanner的使用
5、NSSet的包含关系判断两个集合的交集
聪明在于勤奋,天才在于积累,对于学习语言来说,勤奋和积累是非常必要的,把一个技术点悟透,只有反复不断的练习,达内希望每一位同学都能把学习当成一种信仰,不断的充实自己完善自己。