JSONModel的源码解析

本文详细解析了JSONModel的源码,对比了其与YYModel的区别,包括异常处理、支持特性等方面。核心代码解析部分介绍了如何初始化映射property、使用AssociatedObject缓存等。JSONModel的特点包括动态解析数据类型、使用keyMapper映射、KVC赋值等。此外,还探讨了其在数据转换、类型检查和属性匹配等方面的应用。
摘要由CSDN通过智能技术生成

JSONModel的源码解析

一、JSONModel和YYModel的比较

1、json中有[NSNull null]类型 — JSONModel和YYModel都有适配
2、异常情况:NSString <-> NSNumber — JSONModel和YYModel都有适配
3、异常情况:NSString <-> NSUInteger —JSONModel没有适配,会crash,YYModel有适配
4、异常情况:NSArray <-> NSString —JSONModel和YYModel都有没有适配
5、NSCoding 协议(持久化)的支持 —JSONModel和YYModel都有适配
6、是否可以嵌套Model —JSONModel和YYModel都有适配
7、NSArray中可以包含Model —JSONModel和YYModel都有适配
8、未知字段的适配(向后兼容) —JSONModel和YYModel都有适配
9、继承情况下对于多态的支持 —JSONModel没有适配,YYModel适配了
注意:好像YYModel再gethub上面的更新时间停留在2年前,好像近期都没有更新了。

二、JSONModel的源码解析

我们可以先看看核心代码
1、先是判断传入的字典是否为空,如果为空返回为空的错误
2、再判断传入的数据是否是字典类型,如果不是字典类型不正确的错误
3、核心的代码,通过init方法初始化映射property,(核心代码,等会再下面解释)
4、获取当前类的keyMapper
5、检查映射结构是否能从我们传入的dict中找到对应的数据,如果不能找到,就返回nil,并且抛出错误
6、根据传入的dict进行数据的赋值,如果赋值没有成功,就返回nil,并且抛出错误
7、根据本地的错误来判断是否有错误,如果有错误,就返回nil
8、返回self

-(id)initWithDictionary:(NSDictionary*)dict error:(NSError**)err
{
    //check for nil input
  // 第一步: 先是判断传入的字典是否为空,如果为空返回为空的错误
    if (!dict) {
        if (err) *err = [JSONModelError errorInputIsNil];
        return nil;
    }

    //invalid input, just create empty instance
    //第二步:再判断传入的数据是否是字典类型,如果不是字典类型不正确的错误
    if (![dict isKindOfClass:[NSDictionary class]]) {
        if (err) *err = [JSONModelError errorInvalidDataWithMessage:@"Attempt to initialize JSONModel object using initWithDictionary:error: but the dictionary parameter was not an 'NSDictionary'."];
        return nil;
    }

    //create a class instance
    //第三步:核心的代码,通过init方法初始化映射property
    self = [self init];
    if (!self) {

        //super init didn't succeed
        if (err) *err = [JSONModelError errorModelIsInvalid];
        return nil;
    }
    //第四步:获取当前类的keyMapper
    //key mapping
    JSONKeyMapper* keyMapper = [self __keyMapper];
    //第五步:检查映射结构是否能从我们传入的dict中找到对应的数据,如果不能找到,就返回nil,并且抛出错误
    //check incoming data structure
    if (![self __doesDictionary:dict matchModelWithKeyMapper:keyMapper error:err]) {
        return nil;
    }

    //import the data from a dictionary
    //第六步:根据传入的dict进行数据的赋值,如果赋值没有成功,就返回nil,并且抛出错误。
    if (![self __importDictionary:dict withKeyMapper:keyMapper validation:YES error:err]) {
        return nil;
    }
    //第七步:根据本地的错误来判断是否有错误,如果有错误,就返回nil,并且抛出错误。
    //run any custom model validation
    if (![self validate:err]) {
        return nil;
    }
    //第八步:返回self
    //model is valid! yay!
    return self;
}

第三步:核心代码的解析–通过init方法初始化映射property。
a、他会先调用init方法,init方法中点用了“setup“方法。–[self setup]。

-(id)init
{
    self = [super init];
    if (self) {
        //do initial class setup
        [self __setup__];
    }
    return self;
}

我们先解析一下“setup”方法
1、先是通过AssociateObject来判断是否进行过映射property的缓存,如果没有就使用“__inspectProperties”方法进行映射property的缓存–(后面我会解析一下“__inspectProperties”方法,介绍怎么进行映射property的缓存)
2、获取当前类的keyMapper映射。
3、判断一下,当前的keyMapper是否存在和是否进行映射过,如果没有进行映射就使用AssociateObject方法进行映射。
4、进行AssociateObject映射。

-(void)__setup__
{
    //if first instance of this model, generate the property list
   //第一步: 先是通过AssociateObject来判断是否进行过映射property的缓存,如果没有就使用“__inspectProperties”方法进行映射property的缓存
    if (!objc_getAssociatedObject(self.class, &kClassPropertiesKey)) {
    //进行映射property的缓存
        [self __inspectProperties];
    }

    //if there's a custom key mapper, store it in the associated object
    //第二步:获取keyMapper
    id mapper = [[self class] keyMapper];
    //第三步:判断一下,当前的keyMapper是否存在和是否进行映射过,如果没有进行映射就使用AssociateObject方法进行映射
    if ( mapper && !objc_getAssociatedObject(self.class, &kMapperObjectKey) ) {
    //第四步:进行AssociateObject映射
        objc_setAssociatedObject(
                                 self.class,
                                 &kMapperObjectKey,
                                 mapper,
                                 OBJC_ASSOCIATION_RETAIN // This is atomic
                                 );
    }
}

解析一下“__inspectProperties”方法,介绍怎么进行映射property的缓存
注意:NSScanner是用于在字符串中扫描指定的字符,特别是把它们翻译/转换为数字和别的字符串。可以在创建NSScaner时指定它的string属性,然后scanner会按照你的要求从头到尾地扫描这个字符串的每个字符。
1、先是获取当前class的property列表和个数
2、然后再遍历这些property
3、把我们的property通过一个局部变量进行赋值–JSONModelClassProperty,这个是JSONModel提供的类,来解析每个property。
4、获取property的名称给当前这个局部变量
5、获取这个property的属性
6、判断这个property的属性值里面是否包含”Tc,”,如果包含就设置structName为BOOL
7、扫描property属性
8、设置property的类型
9、判断并设置property的是否是可变的
10、判断property的是否我们允许的json类型
11、解析protocol的string
12、检查property是否为structure
13、判断property是不是Optional
14、判断property是不是Ignored
15、判断property是不是只读属性
16、通过kvc去设置相应的值
17、使用AssociateObject进行缓存

-(void)__inspectProperties
{
    //JMLog(@"Inspect class: %@", [self class]);

    NSMutableDictionary* propertyIndex = [NSMutableDictionary dictionary];

    //temp variables for the loops
    Class class = [self class];
    NSScanner* scanner = nil;
    NSString* propertyType = nil;

    // inspect inherited properties up to the JSONModel class
    while (class != [JSONModel class]) {
        //JMLog(@"inspecting: %@", NSStringFromClass(class));
       //第一步:先是获取当前class的property列表和个数
        unsigned int propertyCount;
        objc_property_t *properties = class_copyPropertyList(class, &propertyCount);
        //第二步:遍历property
        //loop over the class properties
        for (unsigned int i = 0; i < propertyCount; i++) {
//第三步:创建一个解析和判断每个property的局部变量JSONModelClassProperty
            JSONModelClassProperty
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值