zoukankan      html  css  js  c++  java
  • MJExtension源码解读

    MJExtentsion:

    A fast,convenient and nonintrusive conversion framework between JSON and model.

    转换速度快、使用简单方便的字典转模型框架。

    我们经常需要从网络上请求Json数据,然后将其转化成我们自己的模型数据,经常使用的框架有JsonModel、YYModel、OptionalJSONModel和MJExtension,所以现在看一下MJExtension的源码,并记录一下。

    使用MJExtension

    1.pod 'MJExtension'
    2.#import "MJExtension.h"
    3.开始使用

    最简单的使用

    创建一个模型:

    //User.h
    @interface User : NSObject
    
    @property (nonatomic, copy)NSString *name;
    @property (nonatomic, copy)NSString *icon;
    @property (nonatomic, assign)unsigned int age;
    @property (nonatomic, copy)NSString *height;
    @property (nonatomic, strong)NSNumber *money;
    
    @end

    字典转模型:

    //ViewController.m
    NSDictionary *dict = @{
                               @"name" : @"Jack",
                               @"icon" : @"lufy.png",
                               @"age" : @20,
                               @"height" : @"1.55",
                               @"money" : @100.9
                               };
    
        // JSON -> User
        User *user = [User mj_objectWithKeyValues:dict];
        NSLog(@"name=%@, icon=%@, age=%u, height=%@, money=%@", user.name, user.icon, user.age, user.height, user.money);

    打印结果:

    name=Jack, icon=lufy.png, age=20, height=1.55, money=100.9

     通过一句简单的代码,就把字典数据转化为了模型数据,非常方便简洁。

    对于复杂一点的应用

    很多时候json转模型都不是这样简单。有时候会出现模型中嵌套模型或者模型中的属性名和json数据中的key不一致的情况。
    下面看一下一个Student类的模型:

    //Student.h
    @interface Student : NSObject
    
    @property (nonatomic, copy)NSString *ID;
    @property (nonatomic, copy)NSString *desc;
    @property (nonatomic, copy)NSString *nowName;
    @property (nonatomic, copy)NSString *oldName;
    @property (nonatomic, copy)NSString *nameChangedTime;
    @property (nonatomic, strong)Bag *bag;
    
    @end

    我们看到Student模型中嵌套着Bag这个模型:

    //Bag.h
    @interface Bag : NSObject
    
    @property (nonatomic, copy)NSString *name;
    @property ( nonatomic, assign)double *price;
    
    @end

    然后我们再看一下它的json数据的数据结构:

    NSDictionary *dict = @{
                               @"id" : @"20",
                               @"description" : @"kids",
                               @"name" : @{
                                       @"newName" : @"lufy",
                                       @"oldName" : @"kitty",
                                       @"info" : @[
                                               @"test-data",
                                               @{
                                                   @"nameChangedTime" : @"2013-08"
                                                   }
                                               ]
                                       },
                               @"other" : @{
                                       @"bag" : @{
                                               @"name" : @"a red bag",
                                               @"price" : @100.7
                                               }
                                       }
                               };

    我们可以看到字典数据中是id,而模型中是ID,同样也有desc和description。模型中有newName和oldName这些属性,而字典中这些属性在name字段下面。bag属性也是一样的道理,那么怎么办呢?
    我们只需要实现MJExtension中的+ (NSDictionary *)mj_replacedKeyFromPropertyName方法,在Student.m中#import 然后实现+ (NSDictionary *)mj_replacedKeyFromPropertyName方法:

    //Student.m
    + (NSDictionary *)mj_replacedKeyFromPropertyName
    {
        return @{
                 @"ID" : @"id",
                 @"desc" : @"description",
                 @"oldName" : @"name.oldName",
                 @"nowName" : @"name.newName",
                 @"nameChangedTime" : @"name.info[1].nameChangedTime",
                 @"bag" : @"other.bag"
                 };
    }

    这个方法的作用就是在给模型赋值的时候,把右边字段的值赋给模型中左边字段的属性。
    转化一下试试:

    // JSON -> Student
        Student *stu = [Student mj_objectWithKeyValues:dict];
    
        // Printing
        NSLog(@"ID=%@, desc=%@, oldName=%@, nowName=%@, nameChangedTime=%@",
              stu.ID, stu.desc, stu.oldName, stu.nowName, stu.nameChangedTime);
        // ID=20, desc=kids, oldName=kitty, nowName=lufy, nameChangedTime=2013-08
    
        NSLog(@"bagName=%@, bagPrice=%d", stu.bag.name, stu.bag.price);
        // bagName=a red bag, bagPrice=100.700000

    这个地方需要关注一个地方就是模型中的nameChangedTime这个属性,在字典中去取值的时候是取name.info[1].nameChangedTime这个字段的值,这个在后面我们讲核心源码的时候会用到。后面讲源码也会以上面这个为例子来讲,这样比较好理解。

    MJExtension核心类简介

    MJFoundation
    • 这个类中只有一个方法,就是+ (BOOL)isClassFromFoundation:(Class)c,这个方法用来判断一个类是否是foundation类及其子类。

    MJProperty

    这个类非常重要,这个类是对我们类中属性的再封装。
    首先会通过runtime的方法去遍历类中的属性:

    unsigned int count;
        objc_property_t *propertyList = class_copyPropertyList([Student class], &count);
        for (int i = 0; i < count; i++) {
            objc_property_t property = propertyList[i];
            const char *propertyName = property_getName(property);
            const char *attris = property_getAttributes(property);
            NSLog(@"%s %s", propertyName, attris);
        }
    
        free(propertyList);

    打印结果:

    ID T@"NSString",C,N,V_ID
    desc T@"NSString",C,N,V_desc
    nowName T@"NSString",C,N,V_nowName
    oldName T@"NSString",C,N,V_oldName
    nameChangedTime T@"NSString",C,N,V_nameChangedTime
    bag T@"Bag",&,N,V_bag

    通过char类型的attris字符串我们可以看到,它中间有一个串是表示它是属于哪一个类的,比如NSString,Bag。

    通过遍历类的属性,我们得到了objc_property_t类型的属性对象,然后使用这个objc_property_t对象来创建一个对应的MJProperty对象,我们看看MJ大神是怎么做的:

    #pragma mark - 缓存
    + (instancetype)cachedPropertyWithProperty:(objc_property_t)property
    {
        MJExtensionSemaphoreCreate
        MJExtensionSemaphoreWait
        MJProperty *propertyObj = objc_getAssociatedObject(self, property);
        if (propertyObj == nil) {
            propertyObj = [[self alloc] init];
            propertyObj.property = property;
            objc_setAssociatedObject(self, property, propertyObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
        }
        MJExtensionSemaphoreSignal
        return propertyObj;
    }
  • 相关阅读:
    git 知道这些就够了
    接私活可用的 Springboot + Vue 快速开发框架
    Vue 组件传值
    Vue实现点击按钮复制功能
    vue 获取组件高度
    git commit 提交的时候报错husky > pre-commit hook failed (add --no-verify to bypass)(解决办法)
    vue中异步函数async和await的用法
    JS设置浏览器缩放比例
    CSS修改滚动条的样式
    JS代码查看浏览器页面放大比例
  • 原文地址:https://www.cnblogs.com/zhufengshibei/p/10076788.html
Copyright © 2011-2022 走看看