上面一篇文章沒有分析完yymodel 。
接著上篇接著分析
static void ModelSetValueForProperty(__unsafe_unretained id model,
__unsafe_unretained id value,
__unsafe_unretained _YYModelPropertyMeta *meta) {
if (meta->_isCNumber) {
NSNumber *num = YYNSNumberCreateFromID(value);
ModelSetNumberToProperty(model, num, meta);
if (num != nil) [num class]; // hold the number
} else if (meta->_nsType) {
if (value == (id)kCFNull) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
} else {
switch (meta->_nsType) {
case YYEncodingTypeNSString:
case YYEncodingTypeNSMutableString: {
if ([value isKindOfClass:[NSString class]]) {
if (meta->_nsType == YYEncodingTypeNSString) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
} else {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, ((NSString *)value).mutableCopy);
}
} else if ([value isKindOfClass:[NSNumber class]]) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
meta->_setter,
(meta->_nsType == YYEncodingTypeNSString) ?
((NSNumber *)value).stringValue :
((NSNumber *)value).stringValue.mutableCopy);
} else if ([value isKindOfClass:[NSData class]]) {
NSMutableString *string = [[NSMutableString alloc] initWithData:value encoding:NSUTF8StringEncoding];
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, string);
} else if ([value isKindOfClass:[NSURL class]]) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
meta->_setter,
(meta->_nsType == YYEncodingTypeNSString) ?
((NSURL *)value).absoluteString :
((NSURL *)value).absoluteString.mutableCopy);
} else if ([value isKindOfClass:[NSAttributedString class]]) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
meta->_setter,
(meta->_nsType == YYEncodingTypeNSString) ?
((NSAttributedString *)value).string :
((NSAttributedString *)value).string.mutableCopy);
}
} break;
case YYEncodingTypeNSValue:
case YYEncodingTypeNSNumber:
case YYEncodingTypeNSDecimalNumber: {
if (meta->_nsType == YYEncodingTypeNSNumber) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSNumberCreateFromID(value));
} else if (meta->_nsType == YYEncodingTypeNSDecimalNumber) {
if ([value isKindOfClass:[NSDecimalNumber class]]) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
} else if ([value isKindOfClass:[NSNumber class]]) {
NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithDecimal:[((NSNumber *)value) decimalValue]];
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, decNum);
} else if ([value isKindOfClass:[NSString class]]) {
NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithString:value];
NSDecimal dec = decNum.decimalValue;
if (dec._length == 0 && dec._isNegative) {
decNum = nil; // NaN
}
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, decNum);
}
} else { // YYEncodingTypeNSValue
if ([value isKindOfClass:[NSValue class]]) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
}
}
} break;
case YYEncodingTypeNSData:
case YYEncodingTypeNSMutableData: {
if ([value isKindOfClass:[NSData class]]) {
if (meta->_nsType == YYEncodingTypeNSData) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
} else {
NSMutableData *data = ((NSData *)value).mutableCopy;
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, data);
}
} else if ([value isKindOfClass:[NSString class]]) {
NSData *data = [(NSString *)value dataUsingEncoding:NSUTF8StringEncoding];
if (meta->_nsType == YYEncodingTypeNSMutableData) {
data = ((NSData *)data).mutableCopy;
}
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, data);
}
} break;
case YYEncodingTypeNSDate: {
if ([value isKindOfClass:[NSDate class]]) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
} else if ([value isKindOfClass:[NSString class]]) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSDateFromString(value));
}
} break;
case YYEncodingTypeNSURL: {
if ([value isKindOfClass:[NSURL class]]) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
} else if ([value isKindOfClass:[NSString class]]) {
NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSString *str = [value stringByTrimmingCharactersInSet:set];
if (str.length == 0) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, nil);
} else {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, [[NSURL alloc] initWithString:str]);
}
}
} break;
case YYEncodingTypeNSArray:
case YYEncodingTypeNSMutableArray: {
if (meta->_genericCls) {
NSArray *valueArr = nil;
if ([value isKindOfClass:[NSArray class]]) valueArr = value;
else if ([value isKindOfClass:[NSSet class]]) valueArr = ((NSSet *)value).allObjects;
if (valueArr) {
NSMutableArray *objectArr = [NSMutableArray new];
for (id one in valueArr) {
if ([one isKindOfClass:meta->_genericCls]) {
[objectArr addObject:one];
} else if ([one isKindOfClass:[NSDictionary class]]) {
Class cls = meta->_genericCls;
if (meta->_hasCustomClassFromDictionary) {
cls = [cls modelCustomClassForDictionary:one];
if (!cls) cls = meta->_genericCls; // for xcode code coverage
}
NSObject *newOne = [cls new];
[newOne modelSetWithDictionary:one];
if (newOne) [objectArr addObject:newOne];
}
}
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, objectArr);
}
} else {
if ([value isKindOfClass:[NSArray class]]) {
if (meta->_nsType == YYEncodingTypeNSArray) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
} else {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
meta->_setter,
((NSArray *)value).mutableCopy);
}
} else if ([value isKindOfClass:[NSSet class]]) {
if (meta->_nsType == YYEncodingTypeNSArray) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, ((NSSet *)value).allObjects);
} else {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
meta->_setter,
((NSSet *)value).allObjects.mutableCopy);
}
}
}
} break;
case YYEncodingTypeNSDictionary:
case YYEncodingTypeNSMutableDictionary: {
if ([value isKindOfClass:[NSDictionary class]]) {
if (meta->_genericCls) {
NSMutableDictionary *dic = [NSMutableDictionary new];
[((NSDictionary *)value) enumerateKeysAndObjectsUsingBlock:^(NSString *oneKey, id oneValue, BOOL *stop) {
if ([oneValue isKindOfClass:[NSDictionary class]]) {
Class cls = meta->_genericCls;
if (meta->_hasCustomClassFromDictionary) {
cls = [cls modelCustomClassForDictionary:oneValue];
if (!cls) cls = meta->_genericCls; // for xcode code coverage
}
NSObject *newOne = [cls new];
[newOne modelSetWithDictionary:(id)oneValue];
if (newOne) dic[oneKey] = newOne;
}
}];
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, dic);
} else {
if (meta->_nsType == YYEncodingTypeNSDictionary) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
} else {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
meta->_setter,
((NSDictionary *)value).mutableCopy);
}
}
}
} break;
case YYEncodingTypeNSSet:
case YYEncodingTypeNSMutableSet: {
NSSet *valueSet = nil;
if ([value isKindOfClass:[NSArray class]]) valueSet = [NSMutableSet setWithArray:value];
else if ([value isKindOfClass:[NSSet class]]) valueSet = ((NSSet *)value);
if (meta->_genericCls) {
NSMutableSet *set = [NSMutableSet new];
for (id one in valueSet) {
if ([one isKindOfClass:meta->_genericCls]) {
[set addObject:one];
} else if ([one isKindOfClass:[NSDictionary class]]) {
Class cls = meta->_genericCls;
if (meta->_hasCustomClassFromDictionary) {
cls = [cls modelCustomClassForDictionary:one];
if (!cls) cls = meta->_genericCls; // for xcode code coverage
}
NSObject *newOne = [cls new];
[newOne modelSetWithDictionary:one];
if (newOne) [set addObject:newOne];
}
}
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, set);
} else {
if (meta->_nsType == YYEncodingTypeNSSet) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, valueSet);
} else {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
meta->_setter,
((NSSet *)valueSet).mutableCopy);
}
}
} // break; commented for code coverage in next line
default: break;
}
}
} else {
BOOL isNull = (value == (id)kCFNull);
switch (meta->_type & YYEncodingTypeMask) {
case YYEncodingTypeObject: {
Class cls = meta->_genericCls ?: meta->_cls;
if (isNull) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
} else if ([value isKindOfClass:cls] || !cls) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)value);
} else if ([value isKindOfClass:[NSDictionary class]]) {
NSObject *one = nil;
if (meta->_getter) {
one = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
}
if (one) {
[one modelSetWithDictionary:value];
} else {
if (meta->_hasCustomClassFromDictionary) {
cls = [cls modelCustomClassForDictionary:value] ?: cls;
}
one = [cls new];
[one modelSetWithDictionary:value];
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)one);
}
}
} break;
case YYEncodingTypeClass: {
if (isNull) {
((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)NULL);
} else {
Class cls = nil;
if ([value isKindOfClass:[NSString class]]) {
cls = NSClassFromString(value);
if (cls) {
((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)cls);
}
} else {
cls = object_getClass(value);
if (cls) {
if (class_isMetaClass(cls)) {
((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)value);
}
}
}
}
} break;
case? YYEncodingTypeSEL: {
if (isNull) {
((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)NULL);
} else if ([value isKindOfClass:[NSString class]]) {
SEL sel = NSSelectorFromString(value);
if (sel) ((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)sel);
}
} break;
case YYEncodingTypeBlock: {
if (isNull) {
((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())NULL);
} else if ([value isKindOfClass:YYNSBlockClass()]) {
((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())value);
}
} break;
case YYEncodingTypeStruct:
case YYEncodingTypeUnion:
case YYEncodingTypeCArray: {
if ([value isKindOfClass:[NSValue class]]) {
const char *valueType = ((NSValue *)value).objCType;
const char *metaType = meta->_info.typeEncoding.UTF8String;
if (valueType && metaType && strcmp(valueType, metaType) == 0) {
[model setValue:value forKey:meta->_name];
}
}
} break;
case YYEncodingTypePointer:
case YYEncodingTypeCString: {
if (isNull) {
((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, (void *)NULL);
} else if ([value isKindOfClass:[NSValue class]]) {
NSValue *nsValue = value;
if (nsValue.objCType && strcmp(nsValue.objCType, "^v") == 0) {
((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, nsValue.pointerValue);
}
}
} // break; commented for code coverage in next line
default: break;
}
}
}
三百行的代碼
一點點看
這個類三種情況。
第一種情況是meta->_isCNumber =YES
第二種情況是meta->_nsType 有值
再就是其他
第一種情況meta->_isCNumber =YES
調用static force_inline NSNumber *YYNSNumberCreateFromID(__unsafe_unretained id value)
static force_inline NSNumber *YYNSNumberCreateFromID(__unsafe_unretained id value) { static NSCharacterSet *dot; static NSDictionary *dic; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ dot = [NSCharacterSet characterSetWithRange:NSMakeRange('.', 1)]; dic = @{@"TRUE" : @(YES), @"True" : @(YES), @"true" : @(YES), @"FALSE" : @(NO), @"False" : @(NO), @"false" : @(NO), @"YES" : @(YES), @"Yes" : @(YES), @"yes" : @(YES), @"NO" : @(NO), @"No" : @(NO), @"no" : @(NO), @"NIL" : (id)kCFNull, @"Nil" : (id)kCFNull, @"nil" : (id)kCFNull, @"NULL" : (id)kCFNull, @"Null" : (id)kCFNull, @"null" : (id)kCFNull, @"(NULL)" : (id)kCFNull, @"(Null)" : (id)kCFNull, @"(null)" : (id)kCFNull, @"" : (id)kCFNull, @"" : (id)kCFNull, @"" : (id)kCFNull};
});
if (!value || value == (id)kCFNull) return nil;
if ([value isKindOfClass:[NSNumber class]]) return value;
if ([value isKindOfClass:[NSString class]]) {
NSNumber *num = dic[value];
if (num != nil) {
if (num == (id)kCFNull) return nil;
return num;
}
if ([(NSString *)value rangeOfCharacterFromSet:dot].location != NSNotFound) {
const char *cstring = ((NSString *)value).UTF8String;
if (!cstring) return nil;
double num = atof(cstring);
if (isnan(num) || isinf(num)) return nil;
return @(num);
} else {
const char *cstring = ((NSString *)value).UTF8String;
if (!cstring) return nil;
return @(atoll(cstring));
}
}
return nil;
}
這個類簡單,就是講value 轉換成NSNumber
不做介紹
看下面的這個函數 這里面包含怎么將value 賦值到模型上的
static force_inline void ModelSetNumberToProperty(__unsafe_unretained id model,
__unsafe_unretained NSNumber *num,
__unsafe_unretained _YYModelPropertyMeta *meta) {
switch (meta->_type & YYEncodingTypeMask) {
case YYEncodingTypeBool: {
((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)model, meta->_setter, num.boolValue);
} break;
case YYEncodingTypeInt8: {
((void (*)(id, SEL, int8_t))(void *) objc_msgSend)((id)model, meta->_setter, (int8_t)num.charValue);
} break;
case YYEncodingTypeUInt8: {
((void (*)(id, SEL, uint8_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint8_t)num.unsignedCharValue);
} break;
case YYEncodingTypeInt16: {
((void (*)(id, SEL, int16_t))(void *) objc_msgSend)((id)model, meta->_setter, (int16_t)num.shortValue);
} break;
case YYEncodingTypeUInt16: {
((void (*)(id, SEL, uint16_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint16_t)num.unsignedShortValue);
} break;
case YYEncodingTypeInt32: {
((void (*)(id, SEL, int32_t))(void *) objc_msgSend)((id)model, meta->_setter, (int32_t)num.intValue);
}
case YYEncodingTypeUInt32: {
((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint32_t)num.unsignedIntValue);
} break;
case YYEncodingTypeInt64: {
if ([num isKindOfClass:[NSDecimalNumber class]]) {
((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue);
} else {
((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.longLongValue);
}
} break;
case YYEncodingTypeUInt64: {
if ([num isKindOfClass:[NSDecimalNumber class]]) {
((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue);
} else {
((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.unsignedLongLongValue);
}
} break;
case YYEncodingTypeFloat: {
float f = num.floatValue;
if (isnan(f) || isinf(f)) f = 0;
((void (*)(id, SEL, float))(void *) objc_msgSend)((id)model, meta->_setter, f);
} break;
case YYEncodingTypeDouble: {
double d = num.doubleValue;
if (isnan(d) || isinf(d)) d = 0;
((void (*)(id, SEL, double))(void *) objc_msgSend)((id)model, meta->_setter, d);
} break;
case YYEncodingTypeLongDouble: {
long double d = num.doubleValue;
if (isnan(d) || isinf(d)) d = 0;
((void (*)(id, SEL, long double))(void *) objc_msgSend)((id)model, meta->_setter, (long double)d);
} // break; commented for code coverage in next line
default: break;
}
}
賦值好簡單,采用objc_msgSend 方式進行賦值,原來數據就是這樣和model關聯起來的
第二種情況?meta->_nsType 不為0
1 當meta->_nsType == 0 ?給model 屬性值設置nil
2當meta->_nsType==YYEncodingTypeNSString 或者YYEncodingTypeNSMutableString
這里檢查value值是字符串,屬性要是
字符串直接給model 調用setting方法賦值,?
可變字符串,將value轉換成mutableCopy 字符串。
再次檢查 value值是數字,屬性要是
字符串,直接賦值,
可變字符串,將value轉換成mutalbleString
檢查value是NSData ,屬性要是
直接轉換成NSMutableString
檢查value 是NSURL ,屬性要是
要是字符串,直接將value 轉換成字符串
要是可變字符串,直接將value 轉換成可變字符串
檢查value 是NSAttributedString, 屬性要是
要是字符串,直接將value 轉換成字符串
要是可變字符串,直接將value 轉換成可變字符串
從這里可以看出來,NSString 可以接收NSNumber,NSUrl,NSData,NSAttributedString,NSString ,NSMutableString 類型的值
3.當meta->_nsType==YYEncodingTypeNSValue,YYEncodingTypeNSNumber,YYEncodingTypeNSDecimalNumber
當meta->_nsType==YYEncodingTypeNSNumber?
直接給model 賦值
當meta->_nsType == YYEncodingTypeNSDecimalNumber。這里要檢查value的值的類型
可以是NSDecimalNumber,NSNumber,NSString
當meta->_nsType ==YYEncodingTypeNSValue
這里只支持value 是NSValue 類型的值
4 當meta->_nsType==YYEncodingTypeNSData,YYEncodingTypeNSMutableData。檢查value ,可以是NSData 或者NSMutableData NSString
5當meta->_nsType==YYEncodingTypeNSDate ,value 值可以是NSDate 或者NSString
6當meta->_nsType==YYEncodingTypeNSURL value 值可以是NSURL 或者NSString,這里有刪除空白的功能
7.當meta->_nsType ==YYEncodingTypeNSMutableArray,YYEncodingTypeNSArray?
這里value 值可以是NSArray 或者是NSSet
NSMutableArray *objectArr = [NSMutableArray new];
for (id one in valueArr) {
if ([one isKindOfClass:meta->_genericCls]) {
[objectArr addObject:one];
} else if ([one isKindOfClass:[NSDictionary class]]) {
Class cls = meta->_genericCls;
if (meta->_hasCustomClassFromDictionary) {
cls = [cls modelCustomClassForDictionary:one];
if (!cls) cls = meta->_genericCls; // for xcode code coverage
}
NSObject *newOne = [cls new];
[newOne modelSetWithDictionary:one];
if (newOne) [objectArr addObject:newOne];
}
}
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, objectArr);
這里判斷數組中對象是不是_genericCls 對象,是的話就直接將對象放入objectArr 數組中
判斷數組中對象是不是NSDictionary ,是的話,就同解析字典一樣,方式解析該類,將最后的解析結果放入objectArr 中,給model 發送setting方法,出入值objectArr
要是沒有NSArray 對應的模型
我們就直接將value這個數組原裝的的給model。不做處理
8 當meta->_nsType ==YYEncodingTypeNSDictionary ,YYEncodingTypeNSMutableDictionary的時候,這里只支持value 是NSDictionary
當有_genericCls 的時候,取出value 中的所有字典的值,要是其中的值有NSDictionary 的,就對值進行轉換
沒有_genericCls 就根據meta->_nsType類型直接賦值就好
9當meta->_nsType==YYEncodingTypeNSSet,YYEncodingTypeNSMutableSet
處理方式同數組相同
第三種情況?
就是一些特殊情況的處理
1.meta->_type ==YYEncodingTypeObject
當解析屬性是id類型的時候,獲取class,當value時nil 就給model 相關屬性賦值nil
當value值 是 cls 類時候,直接復制就行了,沒有cls 也直接賦值
當value 值是NSDictionary 就將其解析成模型,發送
其他的情況不處理,廢棄掉
2?meta->_type ==YYEncodingTypeClass
value 是nil?就給model 相關屬性賦值nil
value 值是NSString 就將NSString 轉換成class ,給model相關屬性賦值
其他的value 嘗試獲取下class,要是class 是元類的的話,就發送value。
3?meta->_type ==YYEncodingTypeSEL
value 是nil就給model 相關屬性賦值nil
value 是字符串,就將字符串轉換成SEL 給model 屬性賦值
4meta->_type ==YYEncodingTypeBlock
value是nil,給model 發送一個NULL block
別的判斷是不是block
/// Get the 'NSBlock' class.
static force_inline Class YYNSBlockClass() {
static Class cls;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
void (^block)(void) = ^{};
cls = ((NSObject *)block).class;
while (class_getSuperclass(cls) != [NSObject class]) {
cls = class_getSuperclass(cls);
}
});
return cls; // current is "NSBlock"
}
獲取block的根block ?是NSBlock ,檢查value 是NSBlock 給model屬性賦值value
5meta->_type ==YYEncodingTypeStruct,YYEncodingTypeUnion,YYEncodingTypeCArray
這幾種類型,value 只能是NSValue 類型的
6meta->_type==YYEncodingTypePointer,YYEncodingTypeCString
只能接受nsvalue 類型的值,并且特定類型的。
這里就所有json轉model解析完畢了。
我們這里詳細匯總下
1 . ?設計到的類
YYClassInfo
YYClassPropertyInfo
YYClassMethodInfo
YYClassIvarInfo
_YYModelPropertyMeta
_YYModelMeta
NSObject+YYModel
NSArray+YYModel
NSDictionary+YYModel
2 每個類的屬性含義
YYClassInfo ?
@property (nonatomic, assign, readonly) Class cls; ///< class object
類 傳入的參數
@property (nullable, nonatomic, assign, readonly) Class superCls; ///< super class object
自己的父類
@property (nullable, nonatomic, assign, readonly) Class metaCls; ///< class's meta class object
元類
@property (nonatomic, readonly) BOOL isMeta; ///< whether this class is meta class
自己是否是元類
@property (nonatomic, strong, readonly) NSString *name; ///< class name
類的名字
@property (nullable, nonatomic, strong, readonly) YYClassInfo *superClassInfo; ///< super class's class info
父類的解析類
@property (nullable, nonatomic, strong, readonly) NSDictionary*ivarInfos; ///< ivars
類所有的變量字典不包含父類的變量,key是字符串 ,變量的name, value是YYClassIvarInfo
@property (nullable, nonatomic, strong, readonly) NSDictionary*methodInfos; ///< methods
該類的方法,不包含父類的方法 ,key是字符串-方法的name ,value是YYClassMethodInfo
@property (nullable, nonatomic, strong, readonly) NSDictionary*propertyInfos; ///< properties
該類的屬性,不包含父類的方法,key是字符串-屬性的name ,value是YYClassPropertyInfo
YYClassPropertyInfo
@property (nonatomic, assign, readonly) objc_property_t property; ///< property's opaque struct
代表屬性,
@property (nonatomic, strong, readonly) NSString *name; ///< property's name
屬性的名字
@property (nonatomic, assign, readonly) YYEncodingType type; ///< property's type
屬性編碼
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< property's encoding value
屬性修飾類的編碼 eg(該類的NSString 編碼是 NSString * )
@property (nonatomic, strong, readonly) NSString *ivarName; ///< property's ivar name
變量名字
@property (nullable, nonatomic, assign, readonly) Class cls; ///< may be nil
屬性的修飾的類名 ? ?eg:(該條屬性的 Class)
@property (nullable, nonatomic, strong, readonly) NSArray*protocols; ///< may nil
屬性的協議
@property (nonatomic, assign, readonly) SEL getter;? ? ? ? ? ? ? ///< getter (nonnull)
getter方法
@property (nonatomic, assign, readonly) SEL setter;? ? ? ? ? ? ? ///< setter (nonnull)
setting 方法
YYClassMethodInfo
@property (nonatomic, assign, readonly) Method method; ///< method opaque struct
代表類的一個方法
@property (nonatomic, strong, readonly) NSString *name; ///< method name
方法 的名字
@property (nonatomic, assign, readonly) SEL sel; ///< method's selector
方法的SEL
@property (nonatomic, assign, readonly) IMP imp; ///< method's implementation
方法的IMP
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< method's parameter and return types
方法的編碼
@property (nonatomic, strong, readonly) NSString *returnTypeEncoding; ///< return value's type
返回值類型
@property (nullable, nonatomic, strong, readonly) NSArray*argumentTypeEncodings; ///< array of arguments' type
參數類型編碼數組
YYClassIvarInfo
@property (nonatomic, assign, readonly) Ivar ivar; ///< ivar opaque struct
代表一個變量
@property (nonatomic, strong, readonly) NSString *name;? ? ? ? ///< Ivar's name
變量名字
@property (nonatomic, assign, readonly) ptrdiff_t offset;? ? ? ///< Ivar's offset
變量的偏移
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< Ivar's type encoding
變量的編碼 字符串類型
@property (nonatomic, assign, readonly) YYEncodingType type;? ? ///< Ivar's type
變量的編碼 枚舉類型
以上四個類其實就是將Class 給解析成是個部分而已
_YYModelPropertyMeta ?
NSString *_name; ///< property's name
屬性的名字
YYEncodingType _type;? ? ? ? ///< property's type
屬性的類型
YYEncodingNSType _nsType;? ? ///< property's Foundation type
屬性foundataion 類型,
BOOL _isCNumber;? ? ? ? ? ? ///< is c number type
是不是數字
Class _cls;? ? ? ? ? ? ? ? ? ///< property's class, or nil
屬性修飾的名字
Class _genericCls;? ? ? ? ? ///< container's generic class, or nil if threr's no generic class
代表屬性需要轉換成的類
SEL _getter;? ? ? ? ? ? ? ? ///< getter, or nil if the instances cannot respond
屬性的get方法
SEL _setter;? ? ? ? ? ? ? ? ///< setter, or nil if the instances cannot respond
屬性的set方法
BOOL _isKVCCompatible;? ? ? ///< YES if it can access with key-value coding
BOOL _isStructAvailableForKeyedArchiver; ///< YES if the struct can encoded with keyed archiver/unarchiver
特定的NS 結構體CGSize
BOOL _hasCustomClassFromDictionary; ///< class/generic class implements +modelCustomClassForDictionary:
代表 屬性修飾的類 是否實現了modelCustomClassForDictionary: 方法
/*
property->key:? ? ? _mappedToKey:key? ? _mappedToKeyPath:nil? ? ? ? ? ? _mappedToKeyArray:nil
property->keyPath:? _mappedToKey:keyPath _mappedToKeyPath:keyPath(array) _mappedToKeyArray:nil
property->keys:? ? ? _mappedToKey:keys[0] _mappedToKeyPath:nil/keyPath? ? _mappedToKeyArray:keys(array)
*/
NSString *_mappedToKey;? ? ? ///< the key mapped to
匹配json 中key 的名字 。?
NSArray *_mappedToKeyPath;? ///< the key path mapped to (nil if the name is not key path)
NSArray *_mappedToKeyArray;? ///< the key(NSString) or keyPath(NSArray) array (nil if not mapped to multiple keys)
YYClassPropertyInfo *_info;? ///< property's info
代表一條屬性
_YYModelPropertyMeta *_next; ///< next meta if there are multiple properties mapped to the same key.
因為模型中的屬性 更改匹配json中的特定的key。可能導致json中key匹配model中多個屬性,所以用_next標記所有的屬性匹配到的相同的key。?
_YYModelMeta
這個類很關鍵,類似個manger ,將所有的數據組裝起來的
YYClassInfo *_classInfo;
代表一個類,
/// Key:mapped key and key path, Value:_YYModelPropertyMeta.
NSDictionary *_mapper;
key 是json 中的key值,value 是?_YYModelPropertyMeta?
/// Array<_YYModelPropertyMeta>, all property meta of this model.
NSArray *_allPropertyMetas;
代表該類包括父類的所有的屬性。
/// Array<_YYModelPropertyMeta>, property meta which is mapped to a key path.
NSArray *_keyPathPropertyMetas;
/// Array<_YYModelPropertyMeta>, property meta which is mapped to multi keys.
NSArray *_multiKeysPropertyMetas;
/// The number of mapped key (and key path), same to _mapper.count.
NSUInteger _keyMappedCount;
屬性的數量
/// Model class type.
YYEncodingNSType _nsType;
ns類型
BOOL _hasCustomWillTransformFromDictionary;
是否含有modelCustomWillTransformFromDictionary 函數
BOOL _hasCustomTransformFromDictionary;
是否含有modelCustomTransformFromDictionary 函數
BOOL _hasCustomTransformToDictionary;
是否含有modelCustomTransformToDictionary函數
BOOL _hasCustomClassFromDictionary;
是否含有modelCustomClassForDictionary 函數
3 類屬性之間的關聯關系
4 解析思路json 轉 model
《1》 解析model ?,解析成YYClassInfo。
《2》解析YYClassInfo,把self 和superClassInfo 中的每一條屬性,名字作為key ,屬性具體解析成_YYModelPropertyMeta作為值,存放到_YYModelMeta 的_mapper 值中。
《3》遍歷字典 數據,獲取字典的key 和value,檢查_mapper 中是否還有key ,有就從_mapper 中獲取到_YYModelPropertyMeta (代表setting方法)。model 通過_YYModelPropertyMeta(setting方法) 設置value。
《4》這里value是字典,就重復《1》的步驟
《5》這里value是數組,就遍歷value ,每一項重復《1》的步驟
5 要是類實現了方法?modelCustomPropertyMapper,那么設計到的屬性有_YYModelPropertyMeta類中的_mappedToKey,_mappedToKeyPath,_next,_mappedToKeyArray,_keyPathPropertyMetas,_multiKeysPropertyMetas
每個屬性的具體解析
_mappedToKey
該屬性匹配 json中的key(屬性名字和json中 key可以不一樣),正常是屬性的名字和json中的key一樣。
例如
+ (NSDictionary *)modelCustomPropertyMapper {return @{@"statusID" : @"id"}
結果是
_mappedToKey = @"id"
_mappedToKeyPath
要是值是點屬性。該屬性記錄的是以點分割的字符串的數組。
例如
+ (NSDictionary *)modelCustomPropertyMapper {
return @{@"statusID" : @"id.name"}
結果是
_mappedToKeyPath=@[@"id",@"name"]
_mappedToKeyArray
要是值是數組,該屬性記錄的是點分割的字符串的數組
例如
+ (NSDictionary *)modelCustomPropertyMapper {return @{@"statusID" : @[@"id.name"]}
結果是
_mappedToKeyArray=@[@[@"id",@"name"]]
例如+ (NSDictionary *)modelCustomPropertyMapper {return @{@"statusID" : @[@"id"]}
結果是_mappedToKeyArray=@[@"id"]
_keyPathPropertyMetas
包含_mappedToKeyPath不是空 的屬性的數組
_next ?
記錄的是json中的key,需要解析到model中的屬性。
_multiKeysPropertyMetas
包含value 是數組 的屬性的數組
當json 轉換model 調用函數- (BOOL)yy_modelSetWithDictionary:(NSDictionary *)dic
if (modelMeta->_keyPathPropertyMetas) {
? ? ? ? ? ? CFArrayApplyFunction((CFArrayRef)modelMeta->_keyPathPropertyMetas,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_keyPathPropertyMetas)),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ModelSetWithPropertyMetaArrayFunction,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &context);
? ? ? ? }
調用函數
static void ModelSetWithPropertyMetaArrayFunction(const void *_propertyMeta, void *_context) {
? ? ModelSetContext *context = _context;
? ? __unsafe_unretained NSDictionary *dictionary = (__bridge NSDictionary *)(context->dictionary);
? ? __unsafe_unretained _YYModelPropertyMeta *propertyMeta = (__bridge _YYModelPropertyMeta *)(_propertyMeta);
? ? if (!propertyMeta->_setter) return;
? ? id value = nil;
? ? if (propertyMeta->_mappedToKeyArray) {
? ? ? ? value = YYValueForMultiKeys(dictionary, propertyMeta->_mappedToKeyArray);
? ? } else if (propertyMeta->_mappedToKeyPath) {
? ? ? ? value = YYValueForKeyPath(dictionary, propertyMeta->_mappedToKeyPath);
? ? } else {
? ? ? ? value = [dictionary objectForKey:propertyMeta->_mappedToKey];
? ? }
? ? if (value) {
? ? ? ? __unsafe_unretained id model = (__bridge id)(context->model);
? ? ? ? ModelSetValueForProperty(model, value, propertyMeta);
? ? }
}
我們知道,當_keyPathPropertyMetas 不為nil 的時候,對應的是_mappedToKeyPath ,調用下面的函數
static force_inline id YYValueForKeyPath(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *keyPaths) {
? ? id value = nil;
? ? for (NSUInteger i = 0, max = keyPaths.count; i < max; i++) {
? ? ? ? value = dic[keyPaths[i]];
? ? ? ? if (i + 1 < max) {
? ? ? ? ? ? if ([value isKindOfClass:[NSDictionary class]]) {
? ? ? ? ? ? ? ? dic = value;
? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? return nil;
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? return value;
}
這個函數很簡單,按照keyPaths 順序依次查找,要是查找到字典,那么就從新字典里面查找下面的key,其實就是按照kvc path 查找到最后的值。有就匹配,沒有就返回。
這里我們知道_mappedToKeyPath 盛放的數據是 kvc path ,我們把path給用點分割成順序數組。查找與_YYModelPropertyMeta 匹配的字典。
舉個例子
@interface YYTestModel : NSObject
@property (nonatomic ,strong) YYDelegateModel * model;
@property (nonatomic ,strong)NSString * name;
@property (nonatomic ,strong) NSString * userID;
@end
@implementation YYTestModel
+ (NSDictionary *)modelCustomPropertyMapper {
? ? return @{ @"model" : @"user.badge",
? ? ? ? ? ? ? };
}
@end
@interface YYDelegateModel : NSObject
@property (nonatomic ,strong) NSString *zongyiji;
@end
@implementation YYDelegateModel
@end
json數據
{
"user" : {
"badge" : {
"zongyiji" : 1,
}
}
}
調用
YYTestModel * md=[YYTestModel modelWithDictionary:json];
我們這里@"model" : @"user.badge" ?我們這里知道YYTestModel 的_mappedToKeyPath 值是@[@user,@badge] 調用YYValueForKeyPath 方法,
獲取到的值是value值是 ?"zongyiji" : 1, ??
_mappedToKeyArray 這個屬性關聯的函數是
static force_inline id YYValueForMultiKeys(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *multiKeys) {
? ? id value = nil;
? ? for (NSString *key in multiKeys) {
? ? ? ? if ([key isKindOfClass:[NSString class]]) {
? ? ? ? ? ? value = dic[key];
? ? ? ? ? ? if (value) break;
? ? ? ? } else {
? ? ? ? ? ? value = YYValueForKeyPath(dic, (NSArray *)key);
? ? ? ? ? ? if (value) break;
? ? ? ? }
? ? }
? ? return value;
}
我們知道_mappedToKeyArray 可能裝有字符串, 也可能是數組
1 字符串簡單,直接從dic 中獲取到
2要是數組呢, 假設?_mappedToKeyArray 值是@[@[@"id",@"name"],@[@"ss",@"dd"]]
那么先取出@["id",@"name"] 調用YYValueForKeyPath 查詢改kvc 路徑是否包含,要是有的話就返回了。沒有就查找第二條路徑@[@"ss",@"dd"],沒有就結束,有就返回第二條路徑的值。
這里算是把json 轉換成 model完全分析完畢了。
接下來分析model 轉 json
- (id)modelToJSONObject {
? ? /*
? ? Apple said:
? ? The top level object is an NSArray or NSDictionary.
? ? All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
? ? All dictionary keys are instances of NSString.
? ? Numbers are not NaN or infinity.
? ? */
? ? id jsonObject = ModelToJSONObjectRecursive(self);
? ? if ([jsonObject isKindOfClass:[NSArray class]]) return jsonObject;
? ? if ([jsonObject isKindOfClass:[NSDictionary class]]) return jsonObject;
? ? return nil;
}
這里關鍵是下面的這個c函數 static id ModelToJSONObjectRecursive(NSObject *model)
看看具體咋實現的
分段看
if (!model || model == (id)kCFNull) return model;
檢查model 是否合法。不合法就返回自己
if ([model isKindOfClass:[NSString class]]) return model;
檢查model 是字符串,是就返回自己
if ([model isKindOfClass:[NSNumber class]]) return model;
檢查model是NSNumber 就返回自己
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;
? ? }
檢查model是字典,檢查字典是否是有效的json,有效json 就直接返回model。不是有效json 那么,就枚舉字典,value 值重新調用static id ModelToJSONObjectRecursive(NSObject *model) 方法,把數據重新存放到新字典中。
根據官方文檔NSJSONSerialization 中對json 對象的解釋
A Foundation object that may be converted to JSON must have the following properties:
The top level object is an?NSArray?or?NSDictionary.
All objects are instances of?NSString,?NSNumber,?NSArray,?NSDictionary, or?NSNull.
All dictionary keys are instances of?NSString.
Numbers are not NaN or infinity.
Other rules may apply. Calling?isValidJSONObject:?or attempting a conversion are the definitive ways to tell if a given object can be converted to JSON data.
if ([model isKindOfClass:[NSSet class]]) {
? ? ? ? NSArray *array = ((NSSet *)model).allObjects;
? ? ? ? if ([NSJSONSerialization isValidJSONObject:array]) return array;
? ? ? ? NSMutableArray *newArray = [NSMutableArray new];
? ? ? ? for (id obj in array) {
? ? ? ? ? ? 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;
? ? }
要是mode是NSSet ,那么僵set轉換成nsarray,檢查nsarray是否是有效的json 是json,返回array。不是json,那么獲取nsarray 中的每個數據,要是數據是NSString 或者是NSNumber ,就直接加入到新NSArray中,不是就遞歸static id ModelToJSONObjectRecursive(NSObject *model),獲取的數據加入到新NSArray 中,返回新數組
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;
? ? }
要是model 是NSArray ,處理方式同NSSet ,不解釋
if ([model isKindOfClass:[NSURL class]]) return ((NSURL *)model).absoluteString;
要是model是url 那么久返回url的字符串
if ([model isKindOfClass:[NSAttributedString class]]) return ((NSAttributedString *)model).string;
要是model是?NSAttributedString,那么返回model的string
if ([model isKindOfClass:[NSDate class]]) return [YYISODateFormatter() stringFromDate:(id)model];
要是model 是nsdate ,那么就將nsdate 轉換成日期字符串,字符串格式是formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
static force_inline NSDateFormatter *YYISODateFormatter() {
? ? static NSDateFormatter *formatter = nil;
? ? static dispatch_once_t onceToken;
? ? dispatch_once(&onceToken, ^{
? ? ? ? formatter = [[NSDateFormatter alloc] init];
? ? ? ? formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"];
? ? ? ? formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZ";
? ? });
? ? return formatter;
}
if ([model isKindOfClass:[NSData class]]) return nil;
要是model 是nsdata ,那么就返回nil ,因為nsdata 無法不確定是否能轉換成NSString,或者nsnumber,其實這里可以嘗試轉換。
要是都不是以上的類型,那么就是nsobject 類型的
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:[model class]];
? ? if (!modelMeta || modelMeta->_keyMappedCount == 0) return nil;
NSObject 類型,那么就先解析該模型,獲取到該類的?_YYModelMeta(相當于manager)
[modelMeta->_mapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyMappedKey, _YYModelPropertyMeta *propertyMeta, BOOL *stop){
。。。。。
}
枚舉該對象的所有屬性
if (!propertyMeta->_getter) return;
?? id value = nil;
檢查屬性的getter方法,沒有就返回
if (propertyMeta->_isCNumber) {
? ? ? ? ? ? value = ModelCreateNumberFromProperty(model, propertyMeta);
? ? ? }
檢查屬性是不是數字,是數字,就獲取model 通過_YYModelPropertyMeta 的getter方法獲取該屬性的值。這里調用了static force_inline NSNumber *ModelCreateNumberFromProperty(__unsafe_unretained id model,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? __unsafe_unretained _YYModelPropertyMeta *meta) 方法,這個方法很簡單,不做介紹了。
if (propertyMeta->_nsType) {
? ? ? ? ? ? id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
? ? ? ? ? ? value = ModelToJSONObjectRecursive(v);
? ? ? ? }
該條屬性要是_nsType ,我們就獲取該條屬性getter方法的值。將獲取的value 進行調用static id ModelToJSONObjectRecursive(NSObject *model) 方法遞歸。
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;
? ? ? ? ? ? }
檢查屬性的類型,要是YYEncodingTypeObject 類型,還是獲取該model 通過propertyMeta 的getter方法獲取的值,將值進行遞歸。
要是屬性是YYEncodingTypeClass ,那么就通過propertyMeta 的getter方法獲取class值。將class 轉換成字符串。
要是屬性是YYEncodingTypeSEL 方法,同理獲取sel 。將sel 處理成字符串返回
if (!value) return
要是沒有值,那么直接返回
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];
? ? ? ? ? ? ? ? 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 {
? ? ? ? ? ? if (!dic[propertyMeta->_mappedToKey]) {
? ? ? ? ? ? ? ? dic[propertyMeta->_mappedToKey] = value;
? ? ? ? ? ? }
? ? ? ? }
? ? }];
這里要是_mappedToKeyPath 屬性有值,說明是kvc 模式,eg "user.id"
轉換成格式肯定是
{
"user":{
id:"value"
}
}
下面就是進行這樣的轉換,
user 的value 是NSMutableDictionary
id 的value 是 真正的值
第一步獲取superDic 就是跟字典root
第二步 將superDic 設置user 對應的字典subDic
第三步,讓superDic 指向subDic 設置id 對應的值?
要是沒有_mappedToKeyPath 呢?那么就說明沒有kvc 格式匹配。字典設置的key 值是_mappedToKey
就是json 轉model的逆運算,簡單介紹。
static NSString *ModelDescription(NSObject *model)
這個方法也model 手動轉換成json ,原理一樣的。不做介紹了。