MTLJSONSerializing
该协议定义了数据转换之间的规则。需要MTLModel子类去实现。
// 该方法提供属性key与JSON的key path之间的对应关系。注意:如果一个key的对应关系没有被该函数返回,则不将参与JSON序列化。
+ (NSDictionary *)JSONKeyPathsByPropertyKey;
// 可选,通过Model的key获取NSValueTransformer,该方法基本被 +(NSValueTransformer *)key+JSONTransformerForKey;方法替代。
+ (NSValueTransformer *)JSONTransformerForKey:(NSString *)key;
// 指定转换的对象的类型。可选
+ (Class)classForParsingJSONDictionary:(NSDictionary *)JSONDictionary;
MTLJSONAdapter
该类属于数据转换的核心类,转换的过程中该函数需要用户手动调用。
// 该函数提供了讲JSON转为对象的功能。
+ (id)modelOfClass:(Class)modelClass fromJSONDictionary:(NSDictionary *)JSONDictionary error:(NSError **)error
该函数的流程:
- 首先要初始化一个MTLJSONAdapter对象
MTLJSONAdapter *adapter = [[self alloc] initWithModelClass:modelClass];
该初始化的方法中,主要是检查JSONKeyPathsByPropertyKey中定义的合法性,缓存key的对应关系。同时通过以下代码:
_valueTransformersByPropertyKey = [self.class valueTransformersForModelClass:modelClass];
来对每一个key对应的NSValueTransformer(数据解析转换方法)进行缓存,缓存在一个字典中。这些方法有的是通过Model中来。以下几种是Model中实现的转换方式的几个例子,这种函数的格式是:key的name+JSONTransformer:
// NSURL的转换
+ (NSValueTransformer *)HTMLURLJSONTransformer {
return [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName];
}
// 特定key-value转换。通过一个Map
+ (NSValueTransformer *)stateJSONTransformer {
return [NSValueTransformer mtl_valueMappingTransformerWithDictionary:@{
@"open": @(GHIssueStateOpen),
@"closed": @(GHIssueStateClosed)
}];
}
//对象的转换(Model中包含Model),MTLRecursiveUserModel为对象类型)
+ (NSValueTransformer *)ownerJSONTransformer {
return [MTLJSONAdapter dictionaryTransformerWithModelClass:MTLRecursiveUserModel.class];
}
// 数组的转换(Model中包含数组属性),MTLRecursiveUserModel为数组中数据的类型)
+ (NSValueTransformer *)usersJSONTransformer {
return [MTLJSONAdapter arrayTransformerWithModelClass:MTLRecursiveUserModel.class];
}
其他普通的数据类型的转换可以直接使用默认的NSValueTransformer来进行。无需在Model中进行实现对应的方法。
- 然后系统开始序列化数据。
这一步调用以下代码:
[adapter modelFromJSONDictionary:JSONDictionary error:error];
这个函数中,首先要判断Model是否实现了 classForParsingJSONDictionary 这个函数实现,实现了的话就用得讲JSON转换为这个函数中返回的数据类型。
if ([self.modelClass respondsToSelector:@selector(classForParsingJSONDictionary:)]) {
Class class = [self.modelClass classForParsingJSONDictionary:JSONDictionary];
// 处理异常问题
if (class == nil) {
if (error != NULL) {
NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedString(@"Could not parse JSON", @""),
NSLocalizedFailureReasonErrorKey: NSLocalizedString(@"No model class could be found to parse the JSON dictionary.", @"")
};
*error = [NSError errorWithDomain:MTLJSONAdapterErrorDomain code:MTLJSONAdapterErrorNoClassFound userInfo:userInfo];
}
return nil;
}
// 当该协议方法中返回的类和当前原有的类不相同的时候,首先得检查是否实现了MTLJSONSerializing协议、然后就要重新初始化一个MTLJSONAdapter对象,然后开始转换啦。并且直接就return,后面的代码就不管了。
if (class != self.modelClass) {
NSAssert([class conformsToProtocol:@protocol(MTLJSONSerializing)], @"Class %@ returned from +classForParsingJSONDictionary: does not conform to <MTLJSONSerializing>", class);
MTLJSONAdapter *otherAdapter = [self JSONAdapterForModelClass:class error:error];
return [otherAdapter modelFromJSONDictionary:JSONDictionary error:error];
}
}
如果以上协议没有实现。就开始数据解析了,整个过程如下
NSMutableDictionary *dictionaryValue = [[NSMutableDictionary alloc] initWithCapacity:JSONDictionary.count];
// 遍历所有的key,解析每一个key的数据
for (NSString *propertyKey in [self.modelClass propertyKeys]) {
id JSONKeyPaths = self.JSONKeyPathsByPropertyKey[propertyKey];
if (JSONKeyPaths == nil) continue;
id value;
// 获取key对应的value
if ([JSONKeyPaths isKindOfClass:NSArray.class]) {
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
for (NSString *keyPath in JSONKeyPaths) {
BOOL success = NO;
id value = [JSONDictionary mtl_valueForJSONKeyPath:keyPath success:&success error:error];
if (!success) return nil;
if (value != nil) dictionary[keyPath] = value;
}
value = dictionary;
} else {
BOOL success = NO;
value = [JSONDictionary mtl_valueForJSONKeyPath:JSONKeyPaths success:&success error:error];
if (!success) return nil;
}
if (value == nil) continue;
@try {
// 获取key对应的NSValueTransformer,然后使用该NSValueTransformer去转换数据
NSValueTransformer *transformer = self.valueTransformersByPropertyKey[propertyKey];
if (transformer != nil) {
// Map NSNull -> nil for the transformer, and then back for the
// dictionary we're going to insert into.
if ([value isEqual:NSNull.null]) value = nil;
if ([transformer respondsToSelector:@selector(transformedValue:success:error:)]) {
id<MTLTransformerErrorHandling> errorHandlingTransformer = (id)transformer;
BOOL success = YES;
// 对于数组和对象都会重新new一个MTLJSONAdapter,重新执行上面这些步骤,然后对value进行序列化。
value = [errorHandlingTransformer transformedValue:value success:&success error:error];
if (!success) return nil;
} else {
// 这种情况一般是普通数据类型
value = [transformer transformedValue:value];
}
if (value == nil) value = NSNull.null;
}
dictionaryValue[propertyKey] = value;
} @catch (NSException *ex) {
NSLog(@"*** Caught exception %@ parsing JSON key path \"%@\" from: %@", ex, JSONKeyPaths, JSONDictionary);
// Fail fast in Debug builds.
#if DEBUG
@throw ex;
#else
if (error != NULL) {
NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: ex.description,
NSLocalizedFailureReasonErrorKey: ex.reason,
MTLJSONAdapterThrownExceptionErrorKey: ex
};
*error = [NSError errorWithDomain:MTLJSONAdapterErrorDomain code:MTLJSONAdapterErrorExceptionThrown userInfo:userInfo];
}
return nil;
#endif
}
}
// 使用KVC讲value设置给对应的key, modelWithDictionary是MTLModel中定义的类函数,最终还是会调用构造函数 (instancetype)initWithDictionary:(NSDictionary *)dictionaryValue error:(NSError **)error;讲对应的数据通过KVC设置给对象,这样就完成了序列化功能。
id model = [self.modelClass modelWithDictionary:dictionaryValue error:error];
以上就详细的讲解了JSON---->Model的过程。其他的复杂功能暂时没有关注