在不断用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 数据,刚开始不太理解,先了解下这个类是怎么来的,再看看这个地方的代码
// 将 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<YYModel>)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 学习(二)。