介绍
关于MJExtension的介绍、使用官方已经介绍的很清楚了,请前往Github MJExtension.
MJExtension
这个框架可以快速的进行字典转模型,在实际开发中非常方便和稳定。那么这个框架是如果实现的呢?
- 这个框架利用了Runtime获取类的成员属性。
- 这个框架将所有的成员属性都封装成
MJProperty
对象。也就是一个成员属性对应着一个MJProperty
的对象。 - 利用Runtime,对当前类进行一层一层的遍历,当模型类存在继承关系时,也是要进行处理的。
- 该框架不仅提供了字典转模型,也提供了模型转字典中功能。
- 解决了模型嵌套,以及复杂的模型数据问题。
.....
MJProperty的成员属性
对于这个类的理解,应该是对
propertyKeyDict
和objectClassInArrayDict
的理解和运用,关于这个下面有详细的介绍,现在先介绍关于type(成员属性的类型)介绍
type(成员属性的类型)
在该框架中type
也被包装成了一个MJPropertyType
类型的对象。关于MJPropertyType
的成员属性请看下图。
在
MJPropertyType.m
文件中我们会看到以下的一行代码
NSArray *numberTypes = @[MJPropertyTypeInt,MJPropertyTypeShort, MJPropertyTypeBOOL1, MJPropertyTypeBOOL2, MJPropertyTypeFloat, MJPropertyTypeDouble, MJPropertyTypeLong, MJPropertyTypeLongLong, MJPropertyTypeChar];
/**
* 成员变量类型(属性类型)
*/
NSString *const MJPropertyTypeInt = @"i";
NSString *const MJPropertyTypeShort = @"s";
NSString *const MJPropertyTypeFloat = @"f";
NSString *const MJPropertyTypeDouble = @"d";
NSString *const MJPropertyTypeLong = @"l";
NSString *const MJPropertyTypeLongLong = @"q";
NSString *const MJPropertyTypeChar = @"c";
NSString *const MJPropertyTypeBOOL1 = @"c";
NSString *const MJPropertyTypeBOOL2 = @"b";
NSString *const MJPropertyTypePointer = @"*";
NSString *const MJPropertyTypeIvar = @"^{objc_ivar=}";
NSString *const MJPropertyTypeMethod = @"^{objc_method=}";
NSString *const MJPropertyTypeBlock = @"@?";
NSString *const MJPropertyTypeClass = @"#";
NSString *const MJPropertyTypeSEL = @":";
NSString *const MJPropertyTypeId = @"@";
上述代码定义的是成员属性的类型编码,我们可以通过Runtime提供的const char * property_getAttributes(objc_property_t property)
api来可以获取成员属性的描述信息,其中就包含了类型编码。
有关成员属性的描述信息和类型编码可以查看描述信息、类型编码。
成员属性的描述性信息表
声明的属性类型编码表
类型编码表
举个例子
@interface MLStudent : NSObject
@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) int age;
@property (assign, nonatomic) double weight;
@property (assign, nonatomic) double height;
@property (assign, nonatomic) struct objc_method *Method;
@property (assign, nonatomic) struct objc_ivar *Ivar;
@property (assign, nonatomic) void(^block)(void);
@property (strong, nonatomic) MLCar* myCar;
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
unsigned int count;
objc_property_t * property_ts =class_copyPropertyList([MLStudent class], &count);
for (int i = 0; i < count; i ++) {
objc_property_t property_t = property_ts[i];
const char * propertyAttributes_c = property_getAttributes(property_t);
NSString *propertyAttributes = [[NSString alloc] initWithUTF8String:propertyAttributes_c];
NSLog(@"Attributes: %@",propertyAttributes);
NSUInteger dotLoc = [propertyAttributes rangeOfString:@","].location;
NSString *code = nil;
NSUInteger loc = 1;
if (dotLoc == NSNotFound) { // 没有,
code = [propertyAttributes substringFromIndex:loc];
} else {
code = [propertyAttributes substringWithRange:NSMakeRange(loc, dotLoc - loc)];
}
NSLog(@"code: %@",code);
}
}
return 0;
}
输出
通过上图的例子,我们可以获取每个属性的真实类型,在MJExtension
中有一段代码就是获取成员属性的真实类型,然后包装成MJPropertyType
类型的对象
目的就是获取 T后面的真实类型
T@"NSString",C,N,V_name
-
@"NSString"
:代表NSString
类型, -
C
:代表采用copy
策略 -
N
:代表nonatomic
非原子性 -
V_name
: 代表name
成员属性的名字
Ti,N,V_age
-
i
:代表int
类型 -
N
:代表nonatomic
非原子性 -
V_age
:代表age
成员属性的名字
关于下面的类型里面的代码,代码里面介绍以及很详细了。
MJProperty成员属性的赋值流程
上面有提到关于propertyKeysDict
和objectClassInArrayDict
成员属性的理解,这里我采用图解的方式,关于详细的代码,还请查看官网的详细代码。
propertyKeysDict
objectClassInArrayDict
字典转模型
在字典转模型中,可以初略分为两大阶段
第一是准备阶段:
- 将成员属性包装成
MJProperty
对象。 - 对象成员属性type类型的解析和包装
MJPropertyType
. - 将key 以及多级key的拆分和包装
MJPropertyKey
. - 以及对
propertyKeysDict
和objectClassInArrayDict
的赋值。
需要注意的是一个类中有多少个成员属性就会由多少个MJProperty对象,一个MJProperty对象可以拥有多个MJPropertyKey类型的对象(因为key 可能是多级映射)
第二阶段是使用阶段
- 通过回调的方式将MJProperty对象返回给外界的核心处理方法。
- 核心方法采用了通过对类型的判断采取递归的方式进行字典转模型。
- ...
MJEXtension中字典转模型 核心代码解读
- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
- 字典转模型,传入的必须是字典。
- 第一行代码是对象keyValues的处理,如果传入的是json字符串或者其他数据,首先需要转换为字典。
- 第二行代码是对传入类型的判断必须是字典
-
获取当前类的具体类型,通过类来获取那些属性是允许字典转模型,那些熟悉是不允许字典转模型。
解读红色框住的部分
- 通过上述的介绍我们知道
propertyKeysDict
Value是一个二级数组 key是具体的类 - 通过类型和成员属性对象我们就可以通过双层for得到被包装的
MJPropertyKey
对象
3.通过MJPropertyKey
对象属性的name和传入的字典value
,就可得到内层name对应的值,此时在将值赋值给value。(字典可以嵌套字典,通用模型也可以嵌套模型。这样就会出现多级key。在改框架中,对多级key进行了拆分,但是保留了他们的name,通过那么就可以在最外层的字段中查找对应的值了) - 最后对value值的过滤,以及判空处理。
- 获取该成员属性的类型。
- 判断是否是一个类作为成员属性。
- 模型数据的具体类型。
- 标记为1的部分判断
MJProperty *property
是否是Foundation 类型 并且propertyClass
确实存在一个类作为成员属性,那么就进行递归,再次调用高方法。 - 标记为2的部分是处理模型数组作为成员属性的。
最后一步是通过KVC进行赋值。
另外MJExtension提供了模型转字典,后续....