解读MJExtension

介绍

关于MJExtension的介绍、使用官方已经介绍的很清楚了,请前往Github MJExtension.

MJExtension

这个框架可以快速的进行字典转模型,在实际开发中非常方便和稳定。那么这个框架是如果实现的呢?

  1. 这个框架利用了Runtime获取类的成员属性。
  2. 这个框架将所有的成员属性都封装成MJProperty对象。也就是一个成员属性对应着一个MJProperty的对象。
  3. 利用Runtime,对当前类进行一层一层的遍历,当模型类存在继承关系时,也是要进行处理的。
  4. 该框架不仅提供了字典转模型,也提供了模型转字典中功能。
  5. 解决了模型嵌套,以及复杂的模型数据问题。
    .....

MJProperty的成员属性

解读MJExtension_第1张图片
image.png

对于这个类的理解,应该是对 propertyKeyDictobjectClassInArrayDict的理解和运用,关于这个下面有详细的介绍,现在先介绍关于 type(成员属性的类型)介绍

type(成员属性的类型)

在该框架中type也被包装成了一个MJPropertyType类型的对象。关于MJPropertyType的成员属性请看下图。

解读MJExtension_第2张图片
image.png

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来可以获取成员属性的描述信息,其中就包含了类型编码。
有关成员属性的描述信息和类型编码可以查看描述信息、类型编码。

成员属性的描述性信息表


解读MJExtension_第3张图片
image.png

声明的属性类型编码表


解读MJExtension_第4张图片
image.png

类型编码表

解读MJExtension_第5张图片
image.png

以上表格只是参考,建议去官网查询描述信息、类型编码。

举个例子

@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_第6张图片
image.png
解读MJExtension_第7张图片
image.png

通过上图的例子,我们可以获取每个属性的真实类型,在MJExtension中有一段代码就是获取成员属性的真实类型,然后包装成MJPropertyType类型的对象

解读MJExtension_第8张图片
image.png

目的就是获取 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成员属性的赋值流程

解读MJExtension_第9张图片
image.png

上面有提到关于propertyKeysDictobjectClassInArrayDict成员属性的理解,这里我采用图解的方式,关于详细的代码,还请查看官网的详细代码。
propertyKeysDict

解读MJExtension_第10张图片
image.png

objectClassInArrayDict
解读MJExtension_第11张图片
image.png

字典转模型

解读MJExtension_第12张图片
image.png

在字典转模型中,可以初略分为两大阶段

第一是准备阶段

  1. 将成员属性包装成MJProperty对象。
  2. 对象成员属性type类型的解析和包装MJPropertyType.
  3. 将key 以及多级key的拆分和包装MJPropertyKey.
  4. 以及对propertyKeysDictobjectClassInArrayDict的赋值。
    需要注意的是一个类中有多少个成员属性就会由多少个MJProperty对象,一个MJProperty对象可以拥有多个MJPropertyKey类型的对象(因为key 可能是多级映射)

第二阶段是使用阶段

  1. 通过回调的方式将MJProperty对象返回给外界的核心处理方法。
  2. 核心方法采用了通过对类型的判断采取递归的方式进行字典转模型。
  3. ...

MJEXtension中字典转模型 核心代码解读

- (instancetype)mj_setKeyValues:(id)keyValues context:(NSManagedObjectContext *)context

解读MJExtension_第13张图片
image.png

  1. 字典转模型,传入的必须是字典。
  2. 第一行代码是对象keyValues的处理,如果传入的是json字符串或者其他数据,首先需要转换为字典。
  3. 第二行代码是对传入类型的判断必须是字典
  4. 获取当前类的具体类型,通过类来获取那些属性是允许字典转模型,那些熟悉是不允许字典转模型。


    解读MJExtension_第14张图片
    image.png

解读红色框住的部分

  1. 通过上述的介绍我们知道propertyKeysDict Value是一个二级数组 key是具体的类
  2. 通过类型和成员属性对象我们就可以通过双层for得到被包装的MJPropertyKey对象
    3.通过MJPropertyKey对象属性的name和传入的字典value,就可得到内层name对应的值,此时在将值赋值给value。(字典可以嵌套字典,通用模型也可以嵌套模型。这样就会出现多级key。在改框架中,对多级key进行了拆分,但是保留了他们的name,通过那么就可以在最外层的字段中查找对应的值了)
  3. 最后对value值的过滤,以及判空处理。
image.png
  1. 获取该成员属性的类型。
  2. 判断是否是一个类作为成员属性。
  3. 模型数据的具体类型。
解读MJExtension_第15张图片
image.png
  1. 标记为1的部分判断MJProperty *property是否是Foundation 类型 并且propertyClass确实存在一个类作为成员属性,那么就进行递归,再次调用高方法。
  2. 标记为2的部分是处理模型数组作为成员属性的。
image.png

最后一步是通过KVC进行赋值。

另外MJExtension提供了模型转字典,后续....

你可能感兴趣的:(解读MJExtension)