美文网首页
iOS JSON数据解析过程-Mantle

iOS JSON数据解析过程-Mantle

作者: 淡燃 | 来源:发表于2018-09-06 15:42 被阅读0次

    下面是一段json

    {
      "cover": [
        {
          "height": 464,
          "mediaUrl": "T3siZTB7YT1RCvBVdK.jpg",
          "width": 464
        },
        {
          "height": 464,
          "mediaUrl": "T3ohWTBj_T1RCvBVdK.jpg",
          "width": 464
        }
      ],
      "title": "蒹葭苍苍,白露为霜",
      "cretateTime":32938938394,
      "user": {
        "uid": 18222,
        "username": "曹晓文"
      }
    }
    

    JSON的解析过程这里分为三个步骤:

    1. 获取Model类和他父类的属性列表,还有属性的类型
    2. 将JSON转换为我们需要的数据类型,比如字符串、数值、数组,自定义对象,BOOL, URL, 日期
    3. 把转换好的数据赋值给对象的属性property

    下面介绍下具体的实现过程

    1. 获取model类以及父类的属性列表和属性的类型
    • 使用runtime提供的函数去遍历model类所有的属性
      runtime是Objective C的运行时机制,提供了一系列函数,包括获取方法列表、属性列表、变量列表,修改方法、属性,增加方法,属性等等
    • 下面通过class_copyPropertyList获取属性列表,从而获取属性名称
    + (void)enumeratePropertiesUsingBlock:(void (^)(objc_property_t property, BOOL *stop))block {
        Class cls = self;
        BOOL stop = NO;
        while (!stop && ![cls isEqual:MTLModel.class]) {
            unsigned count = 0;
            objc_property_t *properties = class_copyPropertyList(cls, &count);
    
            cls = cls.superclass;
            if (properties == NULL) continue;
    
            @onExit {
                free(properties);
            };
            for (unsigned i = 0; i < count; i++) {
                block(properties[i], &stop);
                if (stop) break;
            }
        }
    }
    
    + (NSDictionary *)mtl_identityPropertyMapWithModel:(Class)modelClass {
        NSCParameterAssert([modelClass conformsToProtocol:@protocol(MTLModel)]);
    
        NSArray *propertyKeys = [modelClass propertyKeys].allObjects;
    
        return [NSDictionary dictionaryWithObjects:propertyKeys forKeys:propertyKeys];
    }
    
    • 通过property_getAttributes获取属性对应的类型
    mtl_propertyAttributes *mtl_copyPropertyAttributes (objc_property_t property) {
        
        const char * const attrString = property_getAttributes(property);
        
        /*attrString 输出之后: T@\"NSString\",C,N,V_name
         T: T 后面是放的是该属性的数据类型
         N: nonatomic
         V: V 后面放的是该属性的变量名称(因为我们知道 @property 实际上只是为我们编写好了 getter 和 setter 方法,并创建一个以下划线开头的变量)
        **/
        ...
        mtl_propertyAttributes *attributes = calloc(1, sizeof(mtl_propertyAttributes) + typeLength + 1);
        ...
        return attributes;
    }
    
    1. 将JSON转换为我们需要的数据类型,比如字符串、数值、数组,自定义对象,BOOL, URL, 日期
      转换器类 MTLValueTransformer, 如果json中的数据类型和我们实际需要的类型不一致的时候,我们也可以自定义一个转换器,转换为我们需要的类型,例如
    //自定义的
    + (NSValueTransformer *)nameJSONTransformer
    {
        return [MTLValueTransformer transformerUsingForwardBlock:^id(id value, BOOL *success, NSError *__autoreleasing *error) {
            //将value转换为合适的类型
            return [value stringValue];
        } reverseBlock:^id(id value, BOOL *success, NSError *__autoreleasing *error) {
            
            return @([value integerValue]);
        }];
    }
    + (NSValueTransformer *)itemsJSONTransformer
    {
        return [MTLJSONAdapter arrayTransformerWithModelClass:[DJRelatedGoodsModel class]];
    }
    //mantle里自带的Transformer
    + (NSValueTransformer *)NSURLJSONTransformer {
        return [NSValueTransformer valueTransformerForName:MTLURLValueTransformerName];
    }
    
    + (NSValueTransformer *)NSUUIDJSONTransformer {
        return [NSValueTransformer valueTransformerForName:MTLUUIDValueTransformerName];
    }
    
    + (NSValueTransformer<MTLTransformerErrorHandling> *)dictionaryTransformerWithModelClass:(Class)modelClass {
        NSParameterAssert([modelClass conformsToProtocol:@protocol(MTLModel)]);
        NSParameterAssert([modelClass conformsToProtocol:@protocol(MTLJSONSerializing)]);
        __block MTLJSONAdapter *adapter;
        
        return [MTLValueTransformer
            transformerUsingForwardBlock:^ id (id JSONDictionary, BOOL *success, NSError **error) {
                if (JSONDictionary == nil) return nil;
                ...
                id model = [adapter modelFromJSONDictionary:JSONDictionary error:error];
                if (model == nil) {
                    *success = NO;
                }
    
                return model;
            }
            reverseBlock:^ NSDictionary * (id model, BOOL *success, NSError **error) {
                if (model == nil) return nil;
                ...
                NSDictionary *result = [adapter JSONDictionaryFromModel:model error:error];
                if (result == nil) {
                    *success = NO;
                }
    
                return result;
            }];
    }
    + (NSValueTransformer<MTLTransformerErrorHandling> *)arrayTransformerWithModelClass:(Class)modelClass {
        id<MTLTransformerErrorHandling> dictionaryTransformer = [self dictionaryTransformerWithModelClass:modelClass];
        
        return [MTLValueTransformer
            transformerUsingForwardBlock:^ id (NSArray *dictionaries, BOOL *success, NSError **error) {
                if (dictionaries == nil) return nil;
                
                ...
                
                NSMutableArray *models = [NSMutableArray arrayWithCapacity:dictionaries.count];
                for (id JSONDictionary in dictionaries) {
                    
                    ...
    
                    id model = [dictionaryTransformer transformedValue:JSONDictionary success:success error:error];
                    
                    ...
                    [models addObject:model];
                }
                
                return models;
            }
            reverseBlock:^ id (NSArray *models, BOOL *success, NSError **error) {
                ...
    
                NSMutableArray *dictionaries = [NSMutableArray arrayWithCapacity:models.count];
                for (id model in models) {
    
                    ...
                    NSDictionary *dict = [dictionaryTransformer reverseTransformedValue:model success:success error:error];
                    
                    ...
                    [dictionaries addObject:dict];
                }
                
                return dictionaries;
            }];
    }
    
    1. 把转换好的数据赋值给对象的属性property
    - (instancetype)initWithDictionary:(NSDictionary *)dictionary error:(NSError **)error {
        self = [self init];
        if (self == nil) return nil;
    
        for (NSString *key in dictionary) {
            
            __autoreleasing id value = [dictionary objectForKey:key];
    
            if ([value isEqual:NSNull.null]) value = nil;
    
            BOOL success = MTLValidateAndSetValue(self, key, value, YES, error);
            //[obj setValue:validatedValue forKey:key];
    
            if (!success) return nil;
        }
    
        return self;
    }
    

    相关文章

      网友评论

          本文标题:iOS JSON数据解析过程-Mantle

          本文链接:https://www.haomeiwen.com/subject/pblxgftx.html