MJExtension源码剖析( 3.0.13)
感觉学习东西最好还是先独立思考,亲自尝试写,然后再学习别人的源代码,这样收获会更多,体会更深,这是我的真实体验。
上一篇简书,说在没看MJExtension源码之前,我自己尝试书写了简易版MJExtension功能框架。而近日探索了MJExtension源码之后,感觉很兴奋,因为我自己写的源码思路基本上和MJExtension源码思路相同,很庆幸! - -
好了,废话少说,看下MJ大神的实现思路。
1,转换JSon对象
参数里面的keyValues对象(可能为字典,NSString,或者Data)预处理统统转化为JSon对象
keyValues = [keyValues mj_JSONObject];
具体转化代码如下
- (id)mj_JSONObject
{
if ([self isKindOfClass:[NSString class]]) {
return [NSJSONSerialization JSONObjectWithData:[((NSString *)self) dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
} else if ([self isKindOfClass:[NSData class]]) {
return [NSJSONSerialization JSONObjectWithData:(NSData *)self options:kNilOptions error:nil];
}
return self.mj_keyValues;
}
2,获取Class的所有属性(关键,核心)
利用OC语言的运行时机制,获取Class的属性,包括基本类型和复合类型属性,从而为后续KVC赋值提供服务。
关键代码如下
objc_property_t *properties = class_copyPropertyList(c, &outCount);
返回的数组里面包含了该类的所有属性,以及该属性所包含的参数(很关键,后面的模型属性需要该参数识别)。
其实之前我也看了OC运行时的获取属性的另外一个函数,就是:
class_copyIvarList(Class _Nullable cls, unsigned int * _Nullable outCount)
OBJC_AVAILABLE(10.5, 2.0, 9.0, 1.0, 2.0);
但是以上函数获取不了属性所对应的属性参数,也就是说,你属性中有一个NSArray,但是利用以上函数根本无法得知模型类型。
3,设置属性类型
为每一个属性设置类型,因为第二步已经拿到了该类的所有属性,就可以设置每一个属性所对应的类型,包括嵌套的model 或者 数组里面装载model,为第四步的赋值做准备。
// 去掉@"和",截取中间的类型名称
_code = [code substringWithRange:NSMakeRange(2, code.length - 3)];
_typeClass = NSClassFromString(_code);
_fromFoundation = [MJFoundation isClassFromFoundation:_typeClass];
_numberType = [_typeClass isSubclassOfClass:[NSNumber class]];
当然MJ大神中间为我们处理很多类型情况,不像我那样只是简单的封装类型。
4,利用KVC赋值
利用OC语言的KVC,为每一个基本类型(包括NSString)赋值
,需要注意的是模型属性是不能直接赋值的,需要利用递归先完成基本类型封装才能进行模型属性的赋值,和我的思路是一致的~
我们可以看到:
if (!type.isFromFoundation && propertyClass) { // 模型属性
value = [propertyClass mj_objectWithKeyValues:value context:context];
}
总结
1,当然MJExtension里面还有原理,内容需要学习,而不是像我所说得那么简单,同时也鼓励大家先亲自思考一边,写一遍,然后再去看。
2,解答了困扰我的2个小问题,①连MJ大神也没找到通过泛型获取数组模型属性,从而推断OC可能尚未支持该功能。②我一直不敢肯定判断模型属性字符串条件,后来看了MJ判断模型语句相似,简单粗暴高效 - -
else if (code.length > 3 && [code hasPrefix:@"@\""]) {
// 去掉@"和",截取中间的类型名称
.....
}
而我写的
if ([attrString containsString:@"T@\""] && [attrString containsString:@"&"] ) {
意思大致相同~
网友评论