YYModel 学习(一)

在不断用YYModel ,越发的发现它的强大,特此学习了解是必须的。还是从其一些基本使用来逐步了解。此篇就以如何转 JSON 字符串为问题进行学习。

- (NSString *)yy_modelToJSONString

也就是上面这个方法的实现,仔细看之后也是发现其核心就是如何返回一个有效的JSON Object,毕竟我们很多时候都不是合法的数据:

static id ModelToJSONObjectRecursive(NSObject *model) {
      // 在这个方法内,进行合理的转换有效JOSN object
}

NSDictionary:不合法的字典处理方式,当其不合法的时候,逐一将其取出,变成有效的JOSN object ,然后就OK啦

if ([model isKindOfClass:[NSDictionary class]]) {
        if ([NSJSONSerialization isValidJSONObject:model]) return model;
        NSMutableDictionary *newDic = [NSMutableDictionary new];
        [((NSDictionary *)model) enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
            NSString *stringKey = [key isKindOfClass:[NSString class]] ? key : key.description;
            if (!stringKey) return;
            id jsonObj = ModelToJSONObjectRecursive(obj);
            if (!jsonObj) jsonObj = (id)kCFNull;
            newDic[stringKey] = jsonObj;
        }];
        return newDic;
    }

NSArray: 不合法的数组的处理方式和不合法的字典处理方式实际上一致的,一一取出,转换成有效的,然后成为新的有效JSON 数据。

if ([model isKindOfClass:[NSArray class]]) {
      if ([NSJSONSerialization isValidJSONObject:model]) return model;
      NSMutableArray *newArray = [NSMutableArray new];
      for (id obj in (NSArray *)model) {
          if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
              [newArray addObject:obj];
          } else {
              id jsonObj = ModelToJSONObjectRecursive(obj);
              if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
          }
      }
      return newArray;
}

YYModelMeta:此处,用到它的目的是让我们类似自定义的Model转化为有效JSON 数据,刚开始不太理解,先了解下这个类是怎么来的,再看看这个地方的代码

YYModel 学习(一)_第1张图片
YYModelMeta
 // 将 model 转换为我们可以操作的 YYModelMeta
    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:[model class]];
    // modelMeta 的类为nil 或它的属性数目为0,则返回 nil
    if (!modelMeta || modelMeta->_keyMappedCount == 0) return nil;
    NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:64];
    // 避免循环使用,在 ARC 环境下为了要兼容 iOS4.x 的版本,用 __unsafe_unretained 替代 __weak 解决强引用循环的问题
    __unsafe_unretained NSMutableDictionary *dic = result;
    // 获取 modelMeta 中的 属性名 和 value
    [modelMeta->_mapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyMappedKey, _YYModelPropertyMeta *propertyMeta, BOOL *stop) {
        if (!propertyMeta->_getter) return;
        // 获取 value ,下面是各种情况的判断(数字、NSFoundation、(id、Class SEL))
        id value = nil;
        if (propertyMeta->_isCNumber) {
            value = ModelCreateNumberFromProperty(model, propertyMeta);
        } else if (propertyMeta->_nsType) {
            id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
            value = ModelToJSONObjectRecursive(v);
        } else {
            switch (propertyMeta->_type & YYEncodingTypeMask) {
                case YYEncodingTypeObject: {
                    id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
                    value = ModelToJSONObjectRecursive(v);
                    if (value == (id)kCFNull) value = nil;
                } break;
                case YYEncodingTypeClass: {
                    Class v = ((Class (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
                    value = v ? NSStringFromClass(v) : nil;
                } break;
                case YYEncodingTypeSEL: {
                    SEL v = ((SEL (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
                    value = v ? NSStringFromSelector(v) : nil;
                } break;
                default: break;
            }
        }
        if (!value) return;
        /**
         获取相应的key,并且赋值 value
         *** 注 意 key 情况的不同 ***
         NSString *_mappedToKey: json 与属性映射的key 如 @{@"name":@"user"}
         NSArray  *_mappedToKeyPath: json 与属性映射的key是一个路径 @{@"name":@"user.name"}
         ;
         */
        if (propertyMeta->_mappedToKeyPath) {
            NSMutableDictionary *superDic = dic;
            NSMutableDictionary *subDic = nil;
            for (NSUInteger i = 0, max = propertyMeta->_mappedToKeyPath.count; i < max; i++) {
                NSString *key = propertyMeta->_mappedToKeyPath[i];
                NSLog(@"key == %@",key);
                if (i + 1 == max) { // end
                    if (!superDic[key]) superDic[key] = value;
                    break;
                }
                subDic = superDic[key];
                if (subDic) {
                    if ([subDic isKindOfClass:[NSDictionary class]]) {
                        subDic = subDic.mutableCopy;
                        superDic[key] = subDic;
                    } else {
                        break;
                    }
                } else {
                    subDic = [NSMutableDictionary new];
                    superDic[key] = subDic;
                }
                superDic = subDic;
                subDic = nil;
            }
        } else {
            // 这个地方就是我们常用的地方,典型的 @{@"name":@"user"}
            if (!dic[propertyMeta->_mappedToKey]) {
                dic[propertyMeta->_mappedToKey] = value;
            }
        }
    }];
    
    // 是否实现了自定义的映射中的转字典
    if (modelMeta->_hasCustomTransformToDictionary) {
        BOOL suc = [((id)model) modelCustomTransformToDictionary:dic];
        // 如果已经实现了,就直接返回,不需要重复做了
        if (!suc) return nil;
    }
    return result;

这样一下来,我们就同样的将自定义model 转化成了我们需要的数据啦。

当然源码中,还有其他诸多类型的验证和转化JOSN String

if (!model || model == (id)kCFNull) return model;
if ([model isKindOfClass:[NSString class]]) return model;
if ([model isKindOfClass:[NSNumber class]]) return model;
if ([model isKindOfClass:[NSURL class]]) return ((NSURL *)model).absoluteString;
if ([model isKindOfClass:[NSAttributedString class]]) return ((NSAttributedString *)model).string;
if ([model isKindOfClass:[NSDate class]]) return [YYISODateFormatter() stringFromDate:(id)model];
if ([model isKindOfClass:[NSData class]]) return nil;

单从转JSON字符串就可以看出,YYModel中可以学习的东西太多了!另外此处的重点是对YYModelMeta的浅尝,后期再深入!继续YYModel 学习(二)。

你可能感兴趣的:(YYModel 学习(一))