JSONModel对外给出了许多常见的初始化方法:
- (instancetype)initWithDictionary:(NSDictionary *)dict error:(NSError **)err;
- (instancetype)initWithData:(NSData *)data error:(NSError **)error;
// Create a new model instance and initialize it with the JSON from a text parameter.
// The method assumes UTF8 encoded input text.
- (instancetype)initWithString:(NSString *)string error:(JSONModelError **)err;
// Create a new model instance and initialize it with the JSON from a text parameter using the given encoding.
- (instancetype)initWithString:(NSString *)string usingEncoding:(NSStringEncoding)encoding error:(JSONModelError **)err;
接下来,我们看一看实现代码:
- (instancetype)initWithData:(NSData *)data error:(NSError *__autoreleasing *)err
{
//check for nil input
if (!data) {
if (err) *err = [JSONModelError errorInputIsNil];
return nil;
}
//read the json
JSONModelError* initError = nil;
id obj = [NSJSONSerialization JSONObjectWithData:data
options:kNilOptions
error:&initError];
if (initError) {
if (err) *err = [JSONModelError errorBadJSON];
return nil;
}
//init with dictionary
id objModel = [self initWithDictionary:obj error:&initError];
if (initError && err) *err = initError;
return objModel;
}
- (id)initWithString:(NSString*)string error:(JSONModelError**)err
{
JSONModelError* initError = nil;
id objModel = [self initWithString:string usingEncoding:NSUTF8StringEncoding error:&initError];
if (initError && err) *err = initError;
return objModel;
}
- (id)initWithString:(NSString *)string usingEncoding:(NSStringEncoding)encoding error:(JSONModelError**)err
{
//check for nil input
if (!string) {
if (err) *err = [JSONModelError errorInputIsNil];
return nil;
}
JSONModelError* initError = nil;
id objModel = [self initWithData:[string dataUsingEncoding:encoding] error:&initError];
if (initError && err) *err = initError;
return objModel;
}
我们发现,这几个初始化方法最终实际上都还是调用了
- (id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err;
在看实现前,我们先看一看:
#pragma mark - associated objects names
static const char * kMapperObjectKey;
// 关联对象kMapperObjectKey
// 保存自定义的mapper
static const char * kClassPropertiesKey;
// 关联对象kClassPropertiesKey
// 用来保存所有属性信息的NSDictionary
static const char * kClassRequiredPropertyNamesKey;
// 关联对象kClassRequiredPropertyNamesKey
// 用来保存所有属性的名称NSSet
static const char * kIndexPropertyNameKey;
大致过程为:
首先,在这个模型类的对象被初始化的时候,遍历自身到所有的父类(直到JSONModel
为止),获取所有的属性,并将其保存在一个字典里。获取传入字典的所有key
,将这些key
与保存的所有属性进行匹配。如果匹配成功,则进行kvc
赋值。
此外,在load
方法里,定义了它的支持:
+ (void)load {
static dispatch_once_t once;
dispatch_once(&once, ^{
@autoreleasepool {
//兼容的对象属性
allowedJSONTypes = @[
[NSString class], [NSNumber class], [NSDecimalNumber class], [NSArray class], [NSDictionary class], [NSNull class], //immutable JSON classes
[NSMutableString class], [NSMutableArray class], [NSMutableDictionary class] //mutable JSON classes
];
//兼容的基本类型属性
allowedPrimitiveTypes = @[
@"BOOL", @"float", @"int", @"long", @"double", @"short",
@"unsigned int", @"usigned long", @"long long", @"unsigned long long", @"unsigned short", @"char", @"unsigned char",
//and some famous aliases
@"NSInteger", @"NSUInteger",
@"Block"
];
//转换器
valueTransformer = [[JSONValueTransformer alloc] init];
//自己的类型
JSONModelClass = NSClassFromString(NSStringFromClass(self));
}
});
}
接下来我们来看看它的实现:
- (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;
}
//create a class instance
//第三步:核心的代码,通过init方法初始化映射property
self = [self init];
if (!self) {
//super init didn't succeed
if (err) *err = [JSONModelError errorModelIsInvalid];
return nil;
}
//check incoming data structure
//第四步:检查映射结构是否能从我们传入的dict中找到对应的数据,如果不能找到,就返回nil,并且抛出错误
if (![self __doesDictionary:dict matchModelWithKeyMapper:self.__keyMapper error:err]) {
return nil;
}
//import the data from a dictionary
//第五步:根据传入的dict进行数据的赋值,如果赋值没有成功,就返回nil,并且抛出错误。
if (![self __importDictionary:dict withKeyMapper:self.__keyMapper validation:YES error:err]) {
return nil;
}
//run any custom model validation
//第六步:根据本地的错误来判断是否有错误,如果有错误,就返回nil,并且抛出错误。
if (![self validate:err]) {
return nil;
}
//model is valid! yay!
//第七步:返回self,model有效,耶嘿!
return self;
}
我们看一下其中的第三步:
//第三步:核心的代码,通过init方法初始化映射property
self = [self init];
看一下它的实现:
- (id)init {
self = [super init];
if (self) {
//do initial class setup
[self __setup__];
}
return self;
}
调用了__setup__
方法。我们来看它的实现:
- (void)__setup__ {
//if first instance of this model, generate the property list
// 第一步:
// 先是通过AssociateObject来判断是否进行过映射property的缓存,
// 如果没有就使用“__inspectProperties”方法进行映射property的缓存
if (!objc_getAssociatedObject(self.class, &kClassPropertiesKey)) {
// 进行映射property的缓存
[self __inspectProperties];
}
//if there's a custom key mapper, store it in the associated object
// 第二步:判断一下,当前的keyMapper是否存在和是否进行映射过,如果没有进行映射就使用AssociateObject方法进行映射
id mapper = [[self class] keyMapper];
if ( mapper && !objc_getAssociatedObject(self.class, &kMapperObjectKey) ) {
//第三步:进行AssociateObject映射
objc_setAssociatedObject(
self.class,
&kMapperObjectKey,
mapper,
OBJC_ASSOCIATION_RETAIN // This is atomic
);
}
}
key mapper
主要是用来针对某些json
字段名和model
数据名不一致的情况。
比如"com.app.test.name":"xxx"
,"test_name":"xxx"
这样的情况,可能对应的model
数据字段名为name
,那如何讲着两个值进行映射,就通过key mapper
来完成。
接下来解析一下__inspectProperties
方法,介绍怎么进行映射property
的缓存。先看实现:
//inspects the class, get's a list of the class properties
//检查类,获取类属性的列表
//它的任务是保存所有需要赋值的属性。
- (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));
// 先是获取当前class的property列表和个数
unsigned int propertyCount;
objc_property_t *properties = class_copyPropertyList(class, &propertyCount);
//loop over the class properties
// 遍历property
for (unsigned int i = 0; i < propertyCount; i++) {
// 创建一个解析和判断每个property的局部变量JSONModelClassProperty
JSONModelClassProperty* p = [[JSONModelClassProperty alloc] init];
//get property name
objc_property_t property = properties[i];
const char *propertyName = property_getName(property);
// 获取property的名称给当前这个局部变量
p.name = @(propertyName);
//JMLog(@"property: %@", p.name);
//get property attributes
// 获取这个property的属性
// 通过property_getAttributes获取property的encode string,解析encode string可以解析出具体property的类型
const char *attrs = property_getAttributes(property);
NSString* propertyAttributes = @(attrs);
NSArray* attributeItems = [propertyAttributes componentsSeparatedByString:@","];
//ignore read-only properties
//忽略只读属性
if ([attributeItems containsObject:@"R"]) {
continue; //to next property
}
// 扫描property属性
scanner = [NSScanner scannerWithString: propertyAttributes];
//JMLog(@"attr: %@", [NSString stringWithCString:attrs encoding:NSUTF8StringEncoding]);
[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]) {
[scanner scanUpToCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"\"<"]
intoString:&propertyType];
//JMLog(@"type: %@", propertyClassName);
// 设置property的类型
p.type = NSClassFromString(propertyType);
// 判断并设置property的是否是可变的
p.isMutable = ([propertyType rangeOfString:@"Mutable"].location != NSNotFound);
// 判断property的是否我们允许的json类型
p.isStandardJSONType = [allowedJSONTypes containsObject:p.type];
//read through the property protocols
// 解析protocol的string
while ([scanner scanString:@"<" intoString:NULL]) {
NSString* protocolName = nil;
[scanner scanUpToString:@">" intoString: &protocolName];
if ([protocolName isEqualToString:@"Optional"]) {
p.isOptional = YES;
} else if([protocolName isEqualToString:@"Index"]) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
p.isIndex = YES;
#pragma GCC diagnostic pop
objc_setAssociatedObject(
self.class,
&kIndexPropertyNameKey,
p.name,
OBJC_ASSOCIATION_RETAIN // This is atomic
);
} else if([protocolName isEqualToString:@"Ignore"]) {
p = nil;
} else {
p.protocol = protocolName;
}
[scanner scanString:@">" intoString:NULL];
}
}
//check if the property is a structure
// 检查property是否为structure
else if ([scanner scanString:@"{" intoString: &propertyType]) {
[scanner scanCharactersFromSet:[NSCharacterSet alphanumericCharacterSet]
intoString:&propertyType];
p.isStandardJSONType = NO;
p.structName = propertyType;
}
//the property must be a primitive
// 属性必须是基本类型,比如int float等
else {
//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];
if (![allowedPrimitiveTypes containsObject:propertyType]) {
//type not allowed - programmer mistaken -> 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);
// 判断property是不是Optional
if([[self class] propertyIsOptional:nsPropertyName]){
p.isOptional = YES;
}
// 判断property是不是Ignored
if([[self class] propertyIsIgnored:nsPropertyName]){
p = nil;
}
Class customClass = [[self class] classForCollectionProperty:nsPropertyName];
if (customClass) {
p.protocol = NSStringFromClass(customClass);
}
//few cases where JSONModel will ignore properties automatically
//在少数情况下,JSONModel 会自动忽略属性
if ([propertyType isEqualToString:@"Block"]) {
p = nil;
}
//add the property object to the temp index
//将属性对象添加到临时索引
// 通过kvc去设置相应的值
if (p && ![propertyIndex objectForKey:p.name]) {
[propertyIndex setValue:p forKey:p.name];
}
// generate custom setters and getter
//生成自定义设置器和获取器
if (p)
{
NSString *name = [p.name stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[p.name substringToIndex:1].uppercaseString];
// getter
SEL getter = NSSelectorFromString([NSString stringWithFormat:@"JSONObjectFor%@", name]);
if ([self respondsToSelector:getter])
p.customGetter = getter;
// setters
p.customSetters = [NSMutableDictionary new];
SEL genericSetter = NSSelectorFromString([NSString stringWithFormat:@"set%@WithJSONObject:", name]);
if ([self respondsToSelector:genericSetter])
p.customSetters[@"generic"] = [NSValue valueWithBytes:&genericSetter objCType:@encode(SEL)];
for (Class type in allowedJSONTypes)
{
NSString *class = NSStringFromClass([JSONValueTransformer classByResolvingClusterClasses:type]);
if (p.customSetters[class])
continue;
SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@With%@:", name, class]);
if ([self respondsToSelector:setter])
p.customSetters[class] = [NSValue valueWithBytes:&setter objCType:@encode(SEL)];
}
}
}
free(properties);
//ascend to the super of the class
//(will do that until it reaches the root class - JSONModel)
class = [class superclass];
}
//finally store the property index in the static property index
//使用AssociateObject进行缓存
objc_setAssociatedObject(
self.class,
&kClassPropertiesKey,
[propertyIndex copy],
OBJC_ASSOCIATION_RETAIN // This is atomic
);
}
通过注释,我们可以大致了解整个过程了。大概提取为:
需要注意几点:
作者利用一个while
函数,获取当前类和当前类的除JSONModel
的所有父类的属性保存在一个字典中。在将来用于和传入的字典进行映射。
作者用JSONModelClassProperty
类封装了JSONModel
的每一个属性。这个类有两个重要的属性:一个是name
,它是属性的名称。另一个是type
,它是属性的类型(例如NSString
)。
作者将属性分为了如下几个类型:
- 对象(不含有协议)。
- 对象(含有协议,属于模型嵌套)。
- 基本数据类型。
- 结构体。
这里面用到了大量的runtime
运行时方法。
objc_property_t *properties = class_copyPropertyList(class, &propertyCount);
class_copyPropertyList()
就是将一个类的属性copy
出来。可以使用函数class_copyPropertyList()
和protocol_copyPropertyList()
分别检索与类(包括加载的类别)和协议关联的属性数组。简单来说就是:
使用runtime
的class_copyPropertyList
方法去获得所有model
对象的property
列表,再使用
property_getAttributes
获得property
的encode string
,通过解析encode string
去获得property
对象的正确含义。
在解析的过程中,使用NSScanner
去扫描encode string
,并使用JSONModelClassProperty
的结构体去保存相关信息。
其中对于protocol
的使用较为特殊,在这里的protocol
并非我们平常当作接口抽象的作用,而是单纯的为了让encode string
中增加相应的字段,可以在解析与赋值的时候给予特定的含义。
接下来研究一下- (BOOL)__doesDictionary:(NSDictionary*)dict matchModelWithKeyMapper:(JSONKeyMapper*)keyMapper error:(NSError**)err;
方法。看一下实现:
- (BOOL)__doesDictionary:(NSDictionary*)dict matchModelWithKeyMapper:(JSONKeyMapper*)keyMapper error:(NSError**)err {
//check if all required properties are present
//第一步:检查一下所有的必要属性都存在,并且把他们都放入set中
NSArray* incomingKeysArray = [dict allKeys];
NSMutableSet* requiredProperties = [self __requiredPropertyNames].mutableCopy;
NSSet* incomingKeys = [NSSet setWithArray: incomingKeysArray];
//transform the key names, if necessary
//第二步:判断是否存在keyMapper映射,如果存在,在对应的set中找到对应的key进行替换
//即如果用户自定义了mapper,则进行转换
if (keyMapper || globalKeyMapper) {
NSMutableSet* transformedIncomingKeys = [NSMutableSet setWithCapacity: requiredProperties.count];
NSString* transformedName = nil;
//loop over the required properties list
//这个是遍历所需要的属性列表
for (JSONModelClassProperty* property in [self __properties__]) {
//获取mapped的关键值transformedName
transformedName = (keyMapper||globalKeyMapper) ? [self __mapString:property.name withKeyMapper:keyMapper] : property.name;
//check if exists and if so, add to incoming keys
//检查该值是否存在,如果存在,加入到incoming集合中
id value;
@try {
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
//第三步:判断那些必须的Properties的集合是否全部都包括
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.class, requiredProperties);
if (err) *err = [JSONModelError errorInvalidDataWithMissingKeys:requiredProperties];
return NO;
}
//not needed anymore
// 不再需要
incomingKeys= nil;
requiredProperties= nil;
return YES;
}
查值的作用主要就是为了能够检查是否model
的所有property
是否都能够被赋值,如果不能则说明缺少值则抛出错误。这边主要就是使用了NSSet
,将dictionary
的所有key
存入一个set
:incomingKeys
,并且将key mapper
映射名进行替换。将刚解析出来的model
所有property
的name
也存入一个set
:requiredProperties
,判断两者是不是包含关系。此外,如果存在了用户自定义的mapper,则需要按照用户的定义来进行转换。
//从字典里获取值并赋给当前模型对象
- (BOOL)__importDictionary:(NSDictionary*)dict withKeyMapper:(JSONKeyMapper*)keyMapper validation:(BOOL)validation error:(NSError**)err {
//loop over the incoming keys and set self's properties
//第一步:循环遍历映射出来的JSONModelClassProperty
for (JSONModelClassProperty* property in [self __properties__]) {
//convert key name to model keys, if a mapper is provided
//第二步:获取keyMapper的映射,获取真正的值
NSString* jsonKeyPath = (keyMapper||globalKeyMapper) ? [self __mapString:property.name withKeyMapper:keyMapper] : property.name;
//JMLog(@"keyPath: %@", jsonKeyPath);
//general check for data type compliance
//数据类型合规性的常规检查
id jsonValue;
@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;
//第三步:判断数据输入的类型是不是我们允许的json类型
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
//第四步:检查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
//第五步:检查自定义的setter,使用对应的set进行赋值
if ([self __customSetValue:jsonValue forProperty:property]) {
//skip to next JSON key
continue;
};
// 0) handle primitives
//如果是基础类型,不如Bool等,我们直接使用kvc进行赋值
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
if (isNull(jsonValue)) {
if ([self valueForKey:property.name] != nil) {
[self setValue:nil forKey: property.name];
}
continue;
}
// 1) check if property is itself a JSONModel
//检查属性是不是JSONModel结构,进行遍历,把所有的结构遍历并且赋值
if ([self __isJSONModelSubClass:property.type]) {
//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 transform for it
// 判断property中是否包含protocol的字段。(该字段主要用来表明array或者dictionary中的对象类型)
if (property.protocol) {
//JMLog(@"proto: %@", p.protocol);
//循环遍历子内容,再将对应的类型赋值给对应的dictionary或者array
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
//判断是否是标准的json类型
if (property.isStandardJSONType && [jsonValue isKindOfClass: property.type]) {
//mutable properties
//判断是否可变的类型
if (property.isMutable) {
jsonValue = [jsonValue mutableCopy];
}
//set the property value
//kvc赋值
if (![jsonValue isEqual:[self valueForKey:property.name]]) {
[self setValue:jsonValue forKey: property.name];
}
continue;
}
// 3.3) handle values to transform
//第六步:处理一些转化类型,比如string <-> number、string <-> url
//做一些基础的判断,是否是对应的类型,是否为空,是否是可变类型,是否是自定义的结构
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)
//下面这句,就是获取真实的json数据的类型
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
//为属性和json对象类构建一个方法选择器
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) {
IMP imp = [valueTransformer methodForSelector:selector];
id (*func)(id, SEL, id) = (void *)imp;
//使用 JSONValueTransformer 进行类型转换
jsonValue = func(valueTransformer, selector, jsonValue);
if (![jsonValue isEqual:[self valueForKey:property.name]])
[self setValue:jsonValue forKey:property.name];
} else {
if (err) {
NSString* msg = [NSString stringWithFormat:@"%@ type not supported for %@.%@", property.type, [self class], property.name];
JSONModelError* dataErr = [JSONModelError errorInvalidDataWithTypeMismatch:msg];
*err = [dataErr errorByPrependingKeyPathComponent:property.name];
}
//解决api返回的数据类型,与jsonmodel中声明的数据类型不一致时的crash
return NO;
}
} else {
// 3.4) handle "all other" cases (if any)
//处理所有其他的case
if (![jsonValue isEqual:[self valueForKey:property.name]])
[self setValue:jsonValue forKey:property.name];
}
}
}
}
return YES;
}
循环遍历model
的每一个解析出来的property
结构,首先从dictioanry
拿出真正对应property
的value
,进行value
一系列的值判断。value
可用的情况下,就开始进行赋值,有setter
方法的通过setter
方法赋值,基础类型int
,float
等直接赋值,如果property
又是一个JSONModel
,就递归先将子Model
进行整体解析。如果包含protocol
字段,则表明内部是一个array
或者dictionary
,并包含这个protocol
字段的对象解析。对于其他情况,应该是一种类型的转换,通过获取值类型和property
类型,调用相应的转换方法进行赋值。
其中值得一提的就是JSONValueTransformer
的类型转化,将数据类型得以正确转换。其目前提供的方法应该是有以下这些:
NSMutableString <-> NSString
NSMutableArray <-> NSArray
NS(Mutable)Array <-> JSONModelArray
NSMutableDictionary <-> NSDictionary
NSSet <-> NSArray
BOOL <-> number/string
string <-> number
string <-> url
string <-> time zone
string <-> date
number <-> date
总的来说JSONModel的源代码有以下特点:
JSONMOdel有以下优点: