JSONModel源码学习<一>
来源:互联网 发布:世界大战红包软件 编辑:程序博客网 时间:2024/04/27 19:15
******************第一段*********************-(id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err{ //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 errorInvalidDataWithMessage:@"Attempt to initialize JSONModel object using initWithDictionary:error: but the dictionary parameter was not an 'NSDictionary'."]; return nil; }//前面两个判断传入的dict是否为空或者是否是 [NSDictionary class] //create a class instance self = [self init];//转入重写的init方法 。。。。。。。后面的在init之后,先看init方法}//重写的init方法-(id)init{ self = [super init]; if (self) { //do initial class setup [self __setup__]; } return self;}//init初始化之后的 setup-(void)__setup__{ //if first instance of this model, generate the property list if (!objc_getAssociatedObject(self.class, &kClassPropertiesKey)) {//是否第一次初始化这个模型类,标准是是否绑定了kClassPropertiesKey,kClassPropertiesKey取出来是数组(存放类的成员变量) [self __inspectProperties];//去遍历成员变量列表,并把遍历好的放到数组中,以kClassPropertiesKey为键绑定:objc_setAssociatedObject, } //if there's a custom key mapper, store it in the associated object id mapper = [[self class] keyMapper];//取出需要进行转换的成员变量名,比如id-->ID,是重写keyMapper返回的JSONKeyMapper类型 if ( mapper && !objc_getAssociatedObject(self.class, &kMapperObjectKey) ) {//如果有,并且是第一次初始化之前没有进行过绑定 objc_setAssociatedObject( self.class, &kMapperObjectKey, mapper, OBJC_ASSOCIATION_RETAIN // This is atomic );//绑定到类上 }}-(void)__inspectProperties//遍历成员变量列表{ //JMLog(@"Inspect class: %@", [self class]); NSMutableDictionary* propertyIndex = [NSMutableDictionary dictionary]; //temp variables for the loops Class class = [self class]; NSScanner* scanner = nil; NSString* propertyType = nil; // inspect inherited properties up to the JSONModel class while (class != [JSONModel class]) {// //JMLog(@"inspecting: %@", NSStringFromClass(class)); unsigned int propertyCount; objc_property_t *properties = class_copyPropertyList(class, &propertyCount);//取出成员变量列表 //loop over the class properties for (unsigned int i = 0; i < propertyCount; i++) { JSONModelClassProperty* p = [[JSONModelClassProperty alloc] init]; //get property name objc_property_t property = properties[i]; const char *propertyName = property_getName(property); p.name = @(propertyName);//成员变量名 //JMLog(@"property: %@", p.name); //get property attributes const char *attrs = property_getAttributes(property);//取出成员变量属性 NSString* propertyAttributes = @(attrs); NSArray* attributeItems = [propertyAttributes componentsSeparatedByString:@","]; //ignore read-only properties 包含 R 的为只读的,不解析 if ([attributeItems containsObject:@"R"]) { continue; //to next property } //check for 64b BOOLs 检查是否是c中字符char ,char 的头是Tc if ([propertyAttributes hasPrefix:@"Tc,"]) { //mask BOOLs as structs so they can have custom convertors p.structName = @"BOOL"; } scanner = [NSScanner scannerWithString: propertyAttributes]; //JMLog(@"attr: %@", [NSString stringWithCString:attrs encoding:NSUTF8StringEncoding]); //把scanner的scanLocation(我理解为光标)移动到T之后 [scanner scanUpToString:@"T" intoString: nil]; [scanner scanString:@"T" intoString:nil]; //check if the property is an instance of a class if ([scanner scanString:@"@\"" intoString: &propertyType]) { //继承自NSObject的类会有 @/" 前缀,例如 "T@\"NSString<PropertyProtocol><PropertyProtocol2>\",C,N,V_type",,移动到@/"之后 [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\"<"] intoString:&propertyType];//扫描到"<(有遵循的协议)或者"(没有遵循的协议)之后,这里的协议只指声明成员变量的时候声明遵循的协议,得到的就是class类,<>里面是遵循的协议,见上面例子 //JMLog(@"type: %@", propertyClassName); p.type = NSClassFromString(propertyType); p.isMutable = ([propertyType rangeOfString:@"Mutable"].location != NSNotFound);//是否是可变的 p.isStandardJSONType = [allowedJSONTypes containsObject:p.type];//是否是允许的类allowedJSONTypes = @[NSString class], [NSNumber class], [NSDecimalNumber class], [NSArray class], [NSDictionary class], [NSNull class],[NSMutableString class], [NSMutableArray class], [NSMutableDictionary class]]; //read through the property protocols while ([scanner scanString:@"<" intoString:NULL]) {//扫描遵循的协议,一个协议一对<>,是否可选、忽略之类的 NSString* protocolName = nil; [scanner scanUpToString:@">" intoString: &protocolName]; if ([protocolName isEqualToString:@"Optional"]) { p.isOptional = YES; } else if([protocolName isEqualToString:@"Index"]) { p.isIndex = YES; objc_setAssociatedObject( self.class, &kIndexPropertyNameKey, p.name, OBJC_ASSOCIATION_RETAIN // This is atomic ); } else if([protocolName isEqualToString:@"ConvertOnDemand"]) { p.convertsOnDemand = YES; } else if([protocolName isEqualToString:@"Ignore"]) { p = nil; } else { p.protocol = protocolName; } [scanner scanString:@">" intoString:NULL]; } } //check if the property is a structure else if ([scanner scanString:@"{" intoString: &propertyType]) {//或者是结构体,CGPoint,CGRect之类的,具体成员变量里为什么会出现这个现在还没有遇到过,官方文档说包含{的是:@property struct YorkshireTeaStruct structDefault;T{YorkshireTeaStruct="pot"i"lady"c},VstructDefault/@property YorkshireTeaStructType typedefDefault;T{YorkshireTeaStruct="pot"i"lady"c},VtypedefDefault/@property union MoneyUnion unionDefault;T(MoneyUnion="alone"f"down"d),VunionDefault [scanner scanCharactersFromSet:[NSCharacterSet alphanumericCharacterSet] intoString:&propertyType]; p.isStandardJSONType = NO; p.structName = propertyType; } //the property must be a primitive else {//原始 数据类型,允许的原始数据类型allowedPrimitiveTypes = @[@"BOOL", @"float", @"int", @"long", @"double", @"short",@"NSInteger", @"NSUInteger", @"Block"]; //the property contains a primitive data type [scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@","] intoString:&propertyType]; //get the full name of the primitive type propertyType = valueTransformer.primitivesNames[propertyType];//取出基本数据类型的全称@{@"f":@"float", @"i":@"int", @"d":@"double", @"l":@"long", @"c":@"BOOL", @"s":@"short", @"q":@"long",@"I":@"NSInteger", @"Q":@"NSUInteger", @"B":@"BOOL",@"@?":@"Block"}; //判断是否是允许的基本数据类型 if (![allowedPrimitiveTypes containsObject:propertyType]) { //type not allowed - programmer mistaked -> exception @throw [NSException exceptionWithName:@"JSONModelProperty type not allowed" reason:[NSString stringWithFormat:@"Property type of %@.%@ is not supported by JSONModel.", self.class, p.name] userInfo:nil]; } } NSString *nsPropertyName = @(propertyName); //基本数据类型定义的时候不能遵循协议,通过类方法判断成员变量遵循的协议 if([[self class] propertyIsOptional:nsPropertyName]){ p.isOptional = YES; } if([[self class] propertyIsIgnored:nsPropertyName]){ p = nil; } NSString* customProtocol = [[self class] protocolForArrayProperty:nsPropertyName]; if (customProtocol) { p.protocol = customProtocol; } //few cases where JSONModel will ignore properties automatically 忽略block的成员变量 if ([propertyType isEqualToString:@"Block"]) { p = nil; } //add the property object to the temp index if (p && ![propertyIndex objectForKey:p.name]) { [propertyIndex setValue:p forKey:p.name]; } } free(properties);//注意:这里释放properties,否则会造成内存泄露 //ascend to the super of the class //(will do that until it reaches the root class - JSONModel) //继续遍历直到基类JSONMedol class = [class superclass]; } //finally store the property index in the static property index //将遍历的结果绑定到类上,这样保证只遍历一次 objc_setAssociatedObject( self.class, &kClassPropertiesKey, [propertyIndex copy], OBJC_ASSOCIATION_RETAIN // This is atomic );}//这里还没有处理如果成员变量是jsonmodel类型,即模型嵌套的处理//**************华丽的分割线,我胡汉三又回来了,哈哈哈**************//回到__setup__,回到init,回到initWithDictionary: error:-(id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err{。。。//接着上面的initWithDictionary: error:{ self = [self init]; if (!self) {//是否初始化成功 //super init didn't succeed if (err) *err = [JSONModelError errorModelIsInvalid]; return nil; } //check incoming data structure //处理需要转换名字的成员变量,并判断传入的字典里有没有model里所有的requiredProperty,如果不全部包括,返回NO if (![self __doesDictionary:dict matchModelWithKeyMapper:self.__keyMapper error:err]) { return nil; } ...}-(BOOL)__doesDictionary:(NSDictionary*)dict matchModelWithKeyMapper:(JSONKeyMapper*)keyMapper error:(NSError**)err{ //check if all required properties are present NSArray* incomingKeysArray = [dict allKeys]; NSMutableSet* requiredProperties = [self __requiredPropertyNames].mutableCopy;//[self __requiredPropertyNames]会对__properties__遍历取出isOptional=NO的,并且通过objc_setAssociatedObject,这样可以只在第一次遍历,后面直接取 NSSet* incomingKeys = [NSSet setWithArray: incomingKeysArray]; //transform the key names, if neccessary //处理有需要转换名字的成员属性 if (keyMapper || globalKeyMapper) { NSMutableSet* transformedIncomingKeys = [NSMutableSet setWithCapacity: requiredProperties.count]; NSString* transformedName = nil; //loop over the required properties list for (JSONModelClassProperty* property in [self __properties__]) { transformedName = (keyMapper||globalKeyMapper) ? [self __mapString:property.name withKeyMapper:keyMapper importing:YES] : property.name; //chek if exists and if so, add to incoming keys id value; @try {//这里没有懂为什么用valueForKeyPath:,没有用valueForKey: value = [dict valueForKeyPath:transformedName]; } @catch (NSException *exception) { value = dict[transformedName]; } if (value) {// [transformedIncomingKeys addObject: property.name]; } } //overwrite the raw incoming list with the mapped key names incomingKeys = transformedIncomingKeys; } //check for missing input keys //利用NSSet的子集 看看要求必有的是否是传入字典的子集 if (![requiredProperties isSubsetOfSet:incomingKeys]) { //get a list of the missing properties //取出没有的成员列表变量,如果有error,赋给error,并返回NO [requiredProperties minusSet:incomingKeys]; //not all required properties are in - invalid input JMLog(@"Incoming data was invalid [%@ initWithDictionary:]. Keys missing: %@", self.class, requiredProperties); if (err) *err = [JSONModelError errorInvalidDataWithMissingKeys:requiredProperties]; return NO; } //not needed anymore incomingKeys= nil; requiredProperties= nil; return YES;}//***********恩,又分割了,part3**********-(id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err{//接上面处理好需要转换名字的成员变量名字和。。。 //import the data from a dictionary //赋值 if (![self __importDictionary:dict withKeyMapper:self.__keyMapper validation:YES error:err]) { return nil; } //run any custom model validation //[self validate:err]应该是预留的接口,现在永远返回YES,翻译:validate-验证,确认 if (![self validate:err]) { return nil; } //model is valid! yay! return self;}//赋值-(BOOL)__importDictionary:(NSDictionary*)dict withKeyMapper:(JSONKeyMapper*)keyMapper validation:(BOOL)validation error:(NSError**)err{ //loop over the incoming keys and set self's properties for (JSONModelClassProperty* property in [self __properties__]) { //convert key name ot model keys, if a mapper is provided NSString* jsonKeyPath = (keyMapper||globalKeyMapper) ? [self __mapString:property.name withKeyMapper:keyMapper importing:YES] : property.name; //JMLog(@"keyPath: %@", jsonKeyPath); //general check for data type compliance id jsonValue;//从jsonDict中以property取值 @try { jsonValue = [dict valueForKeyPath: jsonKeyPath]; } @catch (NSException *exception) { jsonValue = dict[jsonKeyPath]; } //check for Optional properties //取出数据为空 if (isNull(jsonValue)) { //skip this property, continue with next property //如果是可选的继续, if (property.isOptional || !validation) continue; if (err) { //null value for required property NSString* msg = [NSString stringWithFormat:@"Value of required model key %@ is null", property.name]; JSONModelError* dataErr = [JSONModelError errorInvalidDataWithMessage:msg]; *err = [dataErr errorByPrependingKeyPathComponent:property.name]; } return NO; } Class jsonValueClass = [jsonValue class]; BOOL isValueOfAllowedType = NO; //判断返回的数据类型是否是允许的数据类型 for (Class allowedType in allowedJSONTypes) { if ( [jsonValueClass isSubclassOfClass: allowedType] ) { isValueOfAllowedType = YES; break; } } //不是允许的数据类型,报错 if (isValueOfAllowedType==NO) { //type not allowed JMLog(@"Type %@ is not allowed in JSON.", NSStringFromClass(jsonValueClass)); if (err) { NSString* msg = [NSString stringWithFormat:@"Type %@ is not allowed in JSON.", NSStringFromClass(jsonValueClass)]; JSONModelError* dataErr = [JSONModelError errorInvalidDataWithMessage:msg]; *err = [dataErr errorByPrependingKeyPathComponent:property.name]; } return NO; } //check if there's matching property in the model if (property) { // check for custom setter, than the model doesn't need to do any guessing // how to read the property's value from JSON //检查成员变量的set方法,property.setterType默认为kNotInspected(未检查过的),还有kNo(没有set方法),kCustom(正常的set方法,即:setPropertnameWith:),如果有赋值,并返回yes if ([self __customSetValue:jsonValue forProperty:property]) { //skip to next JSON key //有正常的set赋值方法,赋值,continue continue; }; // 0) handle primitives //赋值基本数据类型:不是对象也不是结构体,int、float之类的 if (property.type == nil && property.structName==nil) { //generic setter if (jsonValue != [self valueForKey:property.name]) { [self setValue:jsonValue forKey: property.name]; } //skip directly to the next key continue; } // 0.5) handle nils //判断是否为nil,或者NSNull类型 if (isNull(jsonValue)) { //字典值为空,self之前的值非空,赋空 if ([self valueForKey:property.name] != nil) { [self setValue:nil forKey: property.name]; } continue; } // 1) check if property is itself a JSONMode if ([self __isJSONModelSubClass:property.type]) { //处理jsonModel嵌套 //initialize the property's model, store it JSONModelError* initErr = nil; id value = [[property.type alloc] initWithDictionary: jsonValue error:&initErr]; if (!value) {//解析嵌套模型错误 //skip this property, continue with next property if (property.isOptional || !validation) continue; // Propagate the error, including the property name as the key-path component if((err != nil) && (initErr != nil)) { *err = [initErr errorByPrependingKeyPathComponent:property.name]; } return NO; } //判断是否相等,否则重新赋值 if (![value isEqual:[self valueForKey:property.name]]) { [self setValue:value forKey: property.name]; } //for clarity, does the same without continue continue; } else { // 2) check if there's a protocol to the property // ) might or not be the case there's a built in transofrm for it if (property.protocol) { //JMLog(@"proto: %@", p.protocol); jsonValue = [self __transform:jsonValue forProperty:property error:err]; if (!jsonValue) { if ((err != nil) && (*err == nil)) { NSString* msg = [NSString stringWithFormat:@"Failed to transform value, but no error was set during transformation. (%@)", property]; JSONModelError* dataErr = [JSONModelError errorInvalidDataWithMessage:msg]; *err = [dataErr errorByPrependingKeyPathComponent:property.name]; } return NO; } } // 3.1) handle matching standard JSON types if (property.isStandardJSONType && [jsonValue isKindOfClass: property.type]) { //mutable properties if (property.isMutable) { jsonValue = [jsonValue mutableCopy]; } //set the property value if (![jsonValue isEqual:[self valueForKey:property.name]]) { [self setValue:jsonValue forKey: property.name]; } continue; } // 3.3) handle values to transform if ( (![jsonValue isKindOfClass:property.type] && !isNull(jsonValue)) || //the property is mutable property.isMutable || //custom struct property property.structName ) { // searched around the web how to do this better // but did not find any solution, maybe that's the best idea? (hardly) Class sourceClass = [JSONValueTransformer classByResolvingClusterClasses:[jsonValue class]]; //JMLog(@"to type: [%@] from type: [%@] transformer: [%@]", p.type, sourceClass, selectorName); //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 for custom transformer BOOL foundCustomTransformer = NO; if ([valueTransformer respondsToSelector:selector]) { foundCustomTransformer = YES; } else { //try for hidden custom transformer selectorName = [NSString stringWithFormat:@"__%@",selectorName]; selector = NSSelectorFromString(selectorName); if ([valueTransformer respondsToSelector:selector]) { foundCustomTransformer = YES; } } //check if there's a transformer with that name if (foundCustomTransformer) { //it's OK, believe me...#pragma clang diagnostic push#pragma clang diagnostic ignored "-Warc-performSelector-leaks" //transform the value jsonValue = [valueTransformer performSelector:selector withObject:jsonValue];#pragma clang diagnostic pop if (![jsonValue isEqual:[self valueForKey:property.name]]) { [self setValue:jsonValue forKey: property.name]; } } else { // it's not a JSON data type, and there's no transformer for it // if property type is not supported - that's a programmer mistaked -> exception @throw [NSException exceptionWithName:@"Type not allowed" reason:[NSString stringWithFormat:@"%@ type not supported for %@.%@", property.type, [self class], property.name] userInfo:nil]; return NO; } } else { // 3.4) handle "all other" cases (if any) if (![jsonValue isEqual:[self valueForKey:property.name]]) { [self setValue:jsonValue forKey: property.name]; } } } } } return YES;}
0 0
- JSONModel源码学习<一>
- JSONModel源码阅读笔记
- JSONModel源码阅读笔记
- jsonModel
- JSONModel
- JSONModel
- JSONModel
- JSONModel
- Fiori2.0学习笔记-JSONModel
- iOS YYModel MJExtension JSONModel ----简单学习使用
- lua_gc源码学习一
- tomcat源码学习一
- WordPress源码学习 - 一
- zookeeper源码学习(一)
- Android源码学习(一)
- SharpMap源码学习<一>
- jQuery源码学习(一)
- Srping源码学习一
- Android ListView 点击选中效果
- 应用:《迷宫》游戏代码实现
- 《迷宫》游戏优化
- Android中循环的几种方式
- 字符串概念和定义
- JSONModel源码学习<一>
- 字符串的初始化与引用
- Mac上配置ios开发环境(中)
- 以字符串的形式输入输出
- 字符串结束符使用
- 字符串长度计算方法
- 字符数组和普通数组的区别
- 字符串处理函数(一)
- iOS之Socket编程