首页 > 代码库 > JSONModel源码阅读笔记

JSONModel源码阅读笔记

JSONModel是一个解析服务器返回的Json数据的库。

 

http://blog.csdn.net/dyllove98/article/details/9050905

通常服务器传回的json数据要通过写一个数据转换模块将NSDictionary转换为Model,将NSString数据转换为Model中property的数据类型。

这样服务器如果要做修改,可能需要改两三个文件。

JSONModel的出现就是为了将这种解析工作在设计层面完成。

使用方法:参考连接

对其源码的核心部分JSONModel.m做了源码阅读,笔记如下:

-(id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err
函数中完成所有解析工作:如果有任何失误或者错误直接返回nil。

-(id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err{    //1、做有效性判断(dict是不是空啊,dict是不是真是一个NSDictionary)    //check for nil input    if (!dict) {        if (err) *err = [JSONModelError errorInputIsNil];        return nil;    }    //invalid input, just create empty instance    if (![dict isKindOfClass:[NSDictionary class]]) {        if (err) *err = [JSONModelError errorInvalidData];        return nil;    }    //create a class instance    self = [super init];    if (!self) {                //super init didn‘t succeed        if (err) *err = [JSONModelError errorModelIsInvalid];        return nil;    }        //__setup__中通过调用__restrospectProperties建立类属性的映射表,并且存放在全局变量classProperties里面    //->__restrospectProperties中利用runtime function搞出属性列表:    //    ->获得属性列表class_copyPropertyList(得到objc_property_t数组)->对于每一个objc_property_t调用property_getName获得名称,property_getAttributes获得属性的描述(字符串)->通过解析字符串获得属性的类型、是否是Mutable、是否是基本的JSON类型等等    //    ->调用[class superclass]获得父类继续获取列表    //    ->列表保存在classProperties中备用    //->调用+keyMapper获得key转换列表,生成JSONKeyMapper对象存入keyMapper。    //do initial class setup, retrospec properties    [self __setup__];        //看看必传参数中是否在输入参数中都有。    //check if all required properties are present    NSArray* incomingKeysArray = [dict allKeys];    NSMutableSet* requiredProperties = [self __requiredPropertyNames];    NSSet* incomingKeys = [NSSet setWithArray: incomingKeysArray];        //get the key mapper    JSONKeyMapper* keyMapper = keyMappers[__className_];        //transform the key names, if neccessary    if (keyMapper) {        //对比dict输入的keyName导入NSSet与keyMapper中JSONKeyMapper对象做keyName的转换。统一转换为对象的propertyname。        NSMutableSet* transformedIncomingKeys = [NSMutableSet setWithCapacity: requiredProperties.count];        NSString* transformedName = nil;        //loop over the required properties list        for (NSString* requiredPropertyName in requiredProperties) {            //get the mapped key path            transformedName = keyMapper.modelToJSONKeyBlock(requiredPropertyName);                        //chek if exists and if so, add to incoming keys            if ([dict valueForKeyPath:transformedName]) {                [transformedIncomingKeys addObject: requiredPropertyName];            }        }                //overwrite the raw incoming list with the mapped key names        incomingKeys = transformedIncomingKeys;    }        //利用NSSet的isSubsetOfSet:将必传参数表与输入的keyName表对比。如果不是包含关系说明参数传的不够。    //check for missing input keys    if (![requiredProperties isSubsetOfSet:incomingKeys]) {        //get a list of the missing properties        [requiredProperties minusSet:incomingKeys];        //not all required properties are in - invalid input        JMLog(@"Incoming data was invalid [%@ initWithDictionary:]. Keys missing: %@", self._className_, requiredProperties);                if (err) *err = [JSONModelError errorInvalidDataWithMissingKeys:requiredProperties];        return nil;    }        //not needed anymore    incomingKeys= nil;    requiredProperties= nil;        //从对象的classProperties列表中循环到dict中取值:(赋值使用KVO操作的setValue:forKey:来做的,这样会直接调用setter函数赋值)    //loop over the incoming keys and set self‘s properties    for (JSONModelClassProperty* property in [self __properties__]) {        //对于每一个对象的property,通过keyMapper的转换找到对应dict property的dictKeyPath,找到值jsonValue。如果没有值,并且这个属性是Optional的就进行下一项property对比。        //convert key name ot model keys, if a mapper is provided        NSString* jsonKeyPath = property.name;                if (keyMapper) jsonKeyPath = keyMapper.modelToJSONKeyBlock( property.name );        //JMLog(@"keyPath: %@", jsonKeyPath);                //general check for data type compliance        id jsonValue = http://www.mamicode.com/[dict valueForKeyPath: jsonKeyPath];"Type %@ is not allowed in JSON.", NSStringFromClass(jsonValueClass));            if (err) *err = [JSONModelError errorInvalidData];            return nil;        }                        //check if there‘s matching property in the model        //JSONModelClassProperty* property = classProperties[self.className][key];                //接着对property的属性与jsonValue进行类型匹配:        if (property) {                        //如果是基本类型(int/float等)直接值拷贝;            // 0) handle primitives            if (property.type == nil && property.structName==nil) {                                //just copy the value                [self setValue:jsonValue forKey: property.name];                                //skip directly to the next key                continue;            }                        //如果是NSNull直接赋空值;            // 0.5) handle nils            if (isNull(jsonValue)) {                [self setValue:nil forKey: property.name];                continue;            }            //如果是值也是一个JsonModel,递归搞JsonModel            // 1) check if property is itself a JSONModel            if ([[property.type class] isSubclassOfClass:[JSONModel class]]) {                                //initialize the property‘s model, store it                NSError* initError = nil;                id value = http://www.mamicode.com/[[property.type alloc] initWithDictionary: jsonValue error:&initError];"proto: %@", p.protocol);                                        //__transform:forProperty:函数功能:                    //    ->先判断下protocolClass是否在运行环境中存在,如不存在并且property是NSArray类型,直接报错。否则,直接返回。                    //    ->如果protocalClass是JsonModel的子类,                    //    ->如果property.type是NSArray                    //        ->判断一下是否是使用时转换                    //        ->如果为使用时转换则输出一个JSONModelArray(NSArray)的子类                    //        ->如果不是使用时转换则输出一个NSArray,其中的对象全部转换为protocalClass所对应对象                    //    ->如果property.type是NSDictionary                    //        ->将value转换为protocalClass所对应对象                    //        ->根据key存储到一个NSDictionary中输出                    jsonValue = http://www.mamicode.com/[self __transform:jsonValue forProperty:property];"to type: [%@] from type: [%@] transformer: [%@]", p.type, sourceClass, selectorName);                                        //用字符串拼出转换函数的名称字符串,到JSONValueTransformer中去搜索@SEL执行出正确类型                    //build a method selector for the property and json object classes                    NSString* selectorName = [NSString stringWithFormat:@"%@From%@:",                                              (property.structName? property.structName : property.type), //target name                                              sourceClass]; //source name                    SEL selector = NSSelectorFromString(selectorName);                                        //check if there‘s a transformer with that name                    if ([valueTransformer respondsToSelector:selector]) {                                                //it‘s OK, believe me...#pragma clang diagnostic push#pragma clang diagnostic ignored "-Warc-performSelector-leaks"                        //transform the value                        jsonValue = http://www.mamicode.com/[valueTransformer performSelector:selector withObject:jsonValue];"Type not allowed"                                                       reason:[NSString stringWithFormat:@"%@ type not supported for %@.%@", property.type, [self class], property.name]                                                     userInfo:nil];                        return nil;                    }                                    } else {                    //哪儿都不是的直接存起来                    // 3.4) handle "all other" cases (if any)                    [self setValue:jsonValue forKey: property.name];                }            }        }    }        //最后调用validate:看看结果是不是有效,没问题就返回了。    //run any custom model validation    NSError* validationError = nil;    BOOL doesModelDataValidate = [self validate:&validationError];        if (doesModelDataValidate == NO) {        if (err) *err = validationError;        return nil;    }        //model is valid! yay!    return self;}

程序亮点:
1、为了提高效率通过static的NSArray和NSDictionary进行解耦。
2、JSONValueTransformer实现了一个可复用的类型转换模板。
3、通过runtime function解析出property列表,通过property相关函数解析出名称,和Attributes的信息。
4、NSScanner的使用
5、NSSet的包含关系判断两个集合的交集
6、利用[NSObject setValue:forKey:]的KVO操作赋值,可以直接调用setter函数,并且可以赋nil到property中
7、适时给子类一个函数可以修改父类的一些行为

JSONModel源码阅读笔记