Fork me on GitHub

YYModel解读

前言

YYModel :一个非常轻量级的 JSON 模型自动转换库,代码风格良好且思路清晰,可以从源码中看到作者对 Runtime 深厚的理解。难能可贵的是 YYModel 在其轻量级的代码下还保留着自动类型转换,类型安全,无侵入等特性,并且具有接近手写解析代码的超高性能。

一、先从objc4说起

Class

1
2
3
4
5
6
7
8
9
10
11
12
struct objc_class {
Class isa OBJC_ISA_AVAILABILITY;
Class super_class;
const char *name;
long version;
long info;
long instance_size;
struct objc_ivar_list *ivars;
struct objc_method_list **methodLists;
struct objc_cache *cache;
struct objc_protocol_list *protocols;
};
Method(方法)、Ivar(成员变量)、Property(属性)
1
2
3
typedef struct method_t *Method;
typedef struct ivar_t *Ivar;
typedef struct property_t *objc_property_t;

Method(方法)

1
2
3
4
5
struct objc_method {
SEL method_name;
char *method_types;
IMP method_imp;
};
1
2
3
4
5
6
struct objc_method_list {
struct objc_method_list *obsolete;
int method_count;
int space;
struct objc_method method_list[1];
};
1
2
3
4
struct objc_method_description {
SEL name; /**< The name of the method */
char *types; /**< The types of the method arguments */
};
1
2
3
4
struct objc_method_description_list {
int count;
struct objc_method_description list[1];
};
1
2
3
4
5
6
7
8
9
10
11
//获取方法列表
Method *class_copyMethodList(Class cls, unsigned int *outCount);

//获取方法名
SEL method_getName(Method m);

//获取方法实现
IMP method_getImplementation(Method m);

//获取参数类型和返回类型
const char *method_getTypeEncoding(Method m);

Ivar(成员变量)

1
2
3
4
5
struct objc_ivar_list {
int ivar_count;
int space;
struct objc_ivar ivar_list[1];
};
1
2
3
4
5
6
struct objc_ivar {
char *ivar_name;
char *ivar_type;
int ivar_offset;
int space;
};
1
2
3
4
5
6
7
8
//基地址偏移字节, 对象地址 + ivar偏移字节 -> 访问ivar
ptrdiff_t ivar_getOffset(Ivar ivar);

//成员变量名
const char *ivar_getName(Ivar ivar);

//成员变量类型
const char *ivar_getTypeEncoding(Ivar ivar);

Property(属性)

1
2
3
4
struct property_t {
const char *name;
const char *attributes;
};
1
2
3
4
typedef struct {
const char *name; /**< The name of the attribute */
const char *value; /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;
1
2
3
4
5
6
7
8
//获取Class的属性列表
objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount);

//获取单个属性名称
const char *property_getName(objc_property_t prop);

//获取单个属性详细
const char *property_getAttributes(objc_property_t prop);
1
2
3
//复制单个属性的详细:
objc_property_attribute_t *property_copyAttributeList(objc_property_t prop,
unsigned int *outCount);
举个例子:
1
@property (nonatomic, copy, getter=getName, setter=setName:) NSString *name;
获取name的Attributes<name,value>:
index name value 描述
0 T @\”NSString\” 类型
1 C - copy
2 N - nonatomic
3 G getName getter
4 S setName: setter
5 V _name ivarName

还有很多其他苹果规定的type,具体可查看以下链接:

Type Encodings
Declared Properties

Others

1
2
3
4
5
6
7
struct objc_category {
char *category_name;
char *class_name;
struct objc_method_list *instance_methods;
struct objc_method_list *class_methods;
struct objc_protocol_list *protocols;
};
1
2
3
4
5
struct objc_protocol_list {
struct objc_protocol_list *next;
long count;
__unsafe_unretained Protocol *list[1];
};
1
2
3
4
5
struct objc_cache {
unsigned int mask /* total = mask + 1 */;
unsigned int occupied;
Method buckets[1];
};

二、YYModel文件目录

3个文件:

1
2
3
4
5
6
7
YYModel.h

YYClassInfo.h
YYClassInfo.m

NSObject+YYModel.h
NSObject+YYModel.m

YYModel.h

1
2
3
4
5
6
7
8
9
10
11
12
13
YYModel.h

#import <Foundation/Foundation.h>

#if __has_include(<YYModel/YYModel.h>)
FOUNDATION_EXPORT double YYModelVersionNumber;
FOUNDATION_EXPORT const unsigned char YYModelVersionString[];
#import <YYModel/NSObject+YYModel.h>
#import <YYModel/YYClassInfo.h>
#else
#import "NSObject+YYModel.h"
#import "YYClassInfo.h"
#endif

YYClassInfo:

管理 4个类,分别是对class、ivar、method、property的封装
1
2
3
4
5
6
YYClassInfo.h

@interface YYClassInfo : NSObject
@interface YYClassIvarInfo : NSObject
@interface YYClassMethodInfo : NSObject
@interface YYClassPropertyInfo : NSObject
将 Runtime 层级的一些结构体封装到 NSObject 层级以便调用;
YYClassInfo(NSObject层级) Runtime层级
YYClassInfo objc_class
YYClassIvarInfo objc_ivar
YYClassMethodInfo objc_method
YYClassPropertyInfo property_t

NSObject+YYModel:

主要负责提供方便调用的接口、实现具体的模型转换逻辑(借助YYClassInfo 中的封装)
  • 2个私有类(_YYModelMeta、_YYModelPropertyMeta)
  • 1个主类(NSObject (YYModel))
  • 1个协议(@protocol YYModel
1
2
3
4
5
6
NSObject+YYModel.h

@interface _YYModelMeta : NSObject
@interface _YYModelPropertyMeta : NSObject
@interface NSObject (YYModel)
@protocol YYModel <NSObject>
  • _YYModelMeta :表示Model的类信息,包含YYClassInfo;
  • _YYModelPropertyMeta :表示Model对象的属性信息,包含YYClassPropertyInfo;
以下三者关系:
  • _YYModelMeta、_YYModelPropertyMeta
  • YYClassInfo(NSObject层级)
  • Runtime层级
NSObject+YYModel(逻辑实现层) YYClassInfo(NSObject层级) Runtime层级
_YYModelMeta YYClassInfo objc_class
- YYClassIvarInfo objc_ivar
- YYClassMethodInfo objc_method
_YYModelPropertyMeta YYClassPropertyInfo property_t

三、模型转换逻辑实现

1.JSON转Model分三个步骤:

  • JSON - to - Data
  • Data - to - Dictionary
  • Dictionary - to - Model
1
2
//JSON —> Data
NSData *jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
1
2
//Data —> Dictionary
NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
1
2
3
//dictionary —> Model (一个方法就实现了!)

[self modelSetWithDictionary:dictionary]

2.具体分析 dictionary 转换 Model

主要实现方法:
- (BOOL)modelSetWithDictionary:(NSDictionary *)dic;
看这个方法之前,先看看_YYModelMeta、_YYModelPropertyMeta的包:
_YYModelMeta:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@interface _YYModelMeta : NSObject {
///用于框架类的实例变量,@private太限制,@protected或@public又太开放,就使用这个package吧
@package

///class信息
YYClassInfo *_classInfo;

/// Key:key 和 keyPath, Value:_YYModelPropertyMeta.
NSDictionary *_mapper;

/// Array<_YYModelPropertyMeta>
NSArray *_allPropertyMetas;

/// Array<_YYModelPropertyMeta> path.
NSArray *_keyPathPropertyMetas;

/// Array<_YYModelPropertyMeta> meta 对应多个 key
NSArray *_multiKeysPropertyMetas;

/// key 和 keyPath 个数
NSUInteger _keyMappedCount;

/// Model class type.
YYEncodingNSType _nsType;

/// 用户响应了 "new字典去替换origin字典" 协议方法;json-to-model将要转换;
BOOL _hasCustomWillTransformFromDictionary;

/// 用户响应了 "new字典去替换origin字典" 协议方法;json-to-model已转换;
BOOL _hasCustomTransformFromDictionary;

/// model-to-json额外协议方法:-modelCustomTransformToDictionary:
BOOL _hasCustomTransformToDictionary;

/// json-to-model额外协议方法:+modelCustomClassForDictionary:
BOOL _hasCustomClassFromDictionary;
}
@end
_YYModelPropertyMeta
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@interface _YYModelPropertyMeta : NSObject {
@package

///< 属性名
NSString *_name;

///< 属性type,包含三种类型:
// value(值类型void、UInt8、Block、CArray等)、 // qualifier(限定词,Const、Byref、Oneway等)、
// property(Readonly、Copy、Setter、Dynamic等)、
YYEncodingType _type;

///< 属性Foundation type,比如NSMutableString、NSNumber等
YYEncodingNSType _nsType;

///< 是否C Number类型
BOOL _isCNumber;

///< 属性对应的Class
Class _cls;

///< 数组对应的泛型Class
Class _genericCls;

SEL _getter;
SEL _setter;

///< 是否兼容KVC
BOOL _isKVCCompatible;

///< 结构体是否可以根据key来归解档
BOOL _isStructAvailableForKeyedArchiver;

///< class/generic class implements +modelCustomClassForDictionary:
BOOL _hasCustomClassFromDictionary;

/*
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
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; ///< 属性信息
_YYModelPropertyMeta *_next; ///< 如果一个key对应多个属性的话,next
}
@end
再看两个函数:CFArrayApplyFunction() 和 CFDictionaryApplyFunction()
CF(CoreFoundation)相对NS(Foundation)遍历容器能提升性能
1
2
//遍历字典,将参数context传给applier;需要重写applier方法,接收context;
void CFDictionaryApplyFunction(CFDictionaryRef theDict, CFDictionaryApplierFunction CF_NOESCAPE applier, void *context);
1
2
//遍历数组,将参数context传给applier;需要重写applier方法,接收context;
void CFArrayApplyFunction(CFArrayRef theArray, CFRange range, CFArrayApplierFunction CF_NOESCAPE applier, void *context);
主要实现方法:
- (BOOL)modelSetWithDictionary:(NSDictionary *)dic;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//dictionary 转换 Model主要实现方法
- (BOOL)modelSetWithDictionary:(NSDictionary *)dic {

//1.kCFNull是NSNull的单例,表示空值@{}
if (!dic || dic == (id)kCFNull) return NO;
if (![dic isKindOfClass:[NSDictionary class]]) return NO;

//2.创建_YYModelMeta对象,封装并获取class信息(获取class的ivar、method、property等)
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:object_getClass(self)];
if (modelMeta->_keyMappedCount == 0) return NO;//属性个数为0

//这是YYModel协议中的内容,算是附加功能暂时先忽略
if (modelMeta->_hasCustomWillTransformFromDictionary) {//json-to-model转换之前
dic = [((id<YYModel>)self) modelCustomWillTransformFromDictionary:dic];
if (![dic isKindOfClass:[NSDictionary class]]) return NO;
}

//3.创建结构体(class信息、model对象、dic)
ModelSetContext context = {0};
context.modelMeta = (__bridge void *)(modelMeta);
context.model = (__bridge void *)(self);
context.dictionary = (__bridge void *)(dic);

//4.判断属性个数和字典数量关系
//通常情况是两者相等
//存在3种类型的key(keyPath、keys、key),分别处理
if (modelMeta->_keyMappedCount >= CFDictionaryGetCount((CFDictionaryRef)dic)) {

//字典
CFDictionaryApplyFunction((CFDictionaryRef)dic, ModelSetWithDictionaryFunction, &context);

// 是否存在映射keyPath属性元
if (modelMeta->_keyPathPropertyMetas) {
//数组(keyPath)
CFArrayApplyFunction((CFArrayRef)modelMeta->_keyPathPropertyMetas,
CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_keyPathPropertyMetas)),
ModelSetWithPropertyMetaArrayFunction,
&context);
}

//是否存在一个key映射多个属性元
if (modelMeta->_multiKeysPropertyMetas) {

//数组(keys)
CFArrayApplyFunction((CFArrayRef)modelMeta->_multiKeysPropertyMetas,
CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_multiKeysPropertyMetas)),
ModelSetWithPropertyMetaArrayFunction,
&context);
}
} else {

//数组(key)
CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,
CFRangeMake(0, modelMeta->_keyMappedCount),
ModelSetWithPropertyMetaArrayFunction,
&context);
}

// 忽略
if (modelMeta->_hasCustomTransformFromDictionary) {
return [((id<YYModel>)self) modelCustomTransformFromDictionary:dic];
}
return YES;
}

上述方法主要干了这么几件事:

  • 验证参数(为了程序健壮性一定要这么做)
  • 创建YYModelMeta对象
  • 创建ModelSetContext结构体
  • 将字典用ModelSetWithDictionaryFunction解析(遍历字典去setModel)
  • 根据字典中存在keyPath、keys、key对应的value是数组的情况,都调用ModelSetWithPropertyMetaArrayFunction解析(遍历数组去setModel)
遍历数组
ModelSetWithPropertyMetaArrayFunction
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

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];
}
//必须有value才实现value转property
if (value) {
__unsafe_unretained id model = (__bridge id)(context->model);
//最终每个属性对应的解析方法
ModelSetValueForProperty(model, value, propertyMeta);
}
}
遍历字典
ModelSetWithDictionaryFunction
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

static void ModelSetWithDictionaryFunction(const void *_key, const void *_value, void *_context) {
ModelSetContext *context = _context;
__unsafe_unretained _YYModelMeta *meta = (__bridge _YYModelMeta *)(context->modelMeta);
__unsafe_unretained _YYModelPropertyMeta *propertyMeta = [meta->_mapper objectForKey:(__bridge id)(_key)];
__unsafe_unretained id model = (__bridge id)(context->model);
while (propertyMeta) {

//必须有setter方法才实现value转property
if (propertyMeta->_setter) {

//最终每个属性对应的解析方法
ModelSetValueForProperty(model, (__bridge __unsafe_unretained id)_value, propertyMeta);
}
propertyMeta = propertyMeta->_next;
};
}
最终的解析方法:遍历字典或数组中每一项属性
1
2
3
4

static void ModelSetValueForProperty(__unsafe_unretained id model,
__unsafe_unretained id value,
__unsafe_unretained _YYModelPropertyMeta *meta) {
为了看清实现逻辑,精简代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

static void ModelSetValueForProperty(__unsafe_unretained id model,
__unsafe_unretained id value,
__unsafe_unretained _YYModelPropertyMeta *meta) {
if (meta->_isCNumber) {//是否C Number 类型
NSNumber *num = YYNSNumberCreateFromID(value);//将id类型转换成NSNumber类型
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: {
} break;

case YYEncodingTypeNSValue:
case YYEncodingTypeNSNumber:
case YYEncodingTypeNSDecimalNumber: {
} break;

case YYEncodingTypeNSData:
case YYEncodingTypeNSMutableData: {
} break;

case YYEncodingTypeNSDate: {
} break;

case YYEncodingTypeNSURL: {
} break;

case YYEncodingTypeNSArray:
case YYEncodingTypeNSMutableArray: {
} break;

case YYEncodingTypeNSDictionary:
case YYEncodingTypeNSMutableDictionary: {
} break;

case YYEncodingTypeNSSet:
case YYEncodingTypeNSMutableSet: {
} // break; commented for code coverage in next line

default: break;
}
}
} else {
BOOL isNull = (value == (id)kCFNull);
switch (meta->_type & YYEncodingTypeMask) {
case YYEncodingTypeObject: {
} break;

case YYEncodingTypeClass: {
} break;

case YYEncodingTypeSEL: {
} break;

case YYEncodingTypeBlock: {
} break;

case YYEncodingTypeStruct:
case YYEncodingTypeUnion:
case YYEncodingTypeCArray: {
} break;

case YYEncodingTypePointer:
case YYEncodingTypeCString: {
} // break; commented for code coverage in next line

default: break;
}
}
}
Number类型转成属性
1
2
3
4
5
6
7
8
9
10
11
12
13

static force_inline void ModelSetNumberToProperty(__unsafe_unretained id model,
__unsafe_unretained NSNumber *num,
__unsafe_unretained _YYModelPropertyMeta *meta) {
switch (meta->_type & YYEncodingTypeMask) {
case YYEncodingTypeBool: {

//最终通过objc_msgSend发送消息的形式,实现model的该属性的setter方法
((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)model, meta->_setter, num.boolValue);
} break;
case ...//基本雷同,看上面一行代码就行
}
}
最终通过objc_msgSend发送消息的形式,实现model的该属性的setter方法
1
((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)model, meta->_setter, num.boolValue);
1
2
3
4
5
6
/** objc_msgSend
定义:'为某个类对象发送消息,并且返回一个值'
参数1: 消息接收的对象实例
参数2: 要执行的方法
...: 一系列其他参数 */
id objc_msgSend(id self, SEL op, ...)
1
2
3
4
5
6
7
//实现的伪代码...
id objc_msgSend(id self, SEL op, ...) {
if (!self) return nil;
//关键代码
IMP imp = class_getMethodImplementation(self->isa, SEL op);
imp(self, op, ...);
}
以上大概就是json-to-model整个过程

三、model-to-json过程解析

最后解析的json要满足苹果规定:
  • 最后解析的json一定是字典或数组
  • json内每一项都应该是NSString、NSNumber、NSArray、NSDictionary、NSNull的一种
  • 所有字典的key都应该是NSString
  • 值类型不能是非数值的或无穷的
- (id)modelToJSONObject;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
- (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;
}
static id ModelToJSONObjectRecursive(NSObject *model);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
static id ModelToJSONObjectRecursive(NSObject *model) {

//model为nil、空值、string、number直接返回,不用再往下递归解析
if (!model || model == (id)kCFNull) return model;
if ([model isKindOfClass:[NSString class]]) return model;
if ([model isKindOfClass:[NSNumber class]]) return model;

//字典需要遍历每一项<key,value>,同时创建一个新字典,key必须string;
//value若为nil、空值、string、number则不必再往下解析,直接赋值给新字典;
//value若为字典、数组等,则继续往下递归解析,最终的值也是赋值给新字典;
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;
}

//NSSet
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;
}

//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;
}

//比较特殊的四种类型:NSURL、NSAttributedString、NSDate、NSData
//NSURL返回完整的url字符串
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;


//如果是model是类创建的对象,则需要将model的属性(key、keyPath、keys)方式解析
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:[model class]];

//属性个数为0
if (!modelMeta || modelMeta->_keyMappedCount == 0) return nil;

//将该model转化成字典
NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:64];

//__unsafe_unretained 的好处就是 编译器不用去管理内存,提高性能
__unsafe_unretained NSMutableDictionary *dic = result; // avoid retain and release in block

//按照属性key、keys、keyPath遍历
[modelMeta->_mapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyMappedKey, _YYModelPropertyMeta *propertyMeta, BOOL *stop) {

//最终是通过objc_sendMsg调用getter获取value
if (!propertyMeta->_getter) return;

id value = nil;
if (propertyMeta->_isCNumber) {

//C Number 的方式getter Value
value = ModelCreateNumberFromProperty(model, propertyMeta);

//NS类型:NSString、NSArray等
} else if (propertyMeta->_nsType) {

//最底层的objc_msgSend调用,取出的值继续递归解析,其他情况雷同,不一一看了
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;

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;
}
}
}];

if (modelMeta->_hasCustomTransformToDictionary) {
BOOL suc = [((id<YYModel>)model) modelCustomTransformToDictionary:dic];
if (!suc) return nil;
}
return result;
}
以上大概就是model-to-json的过程

另外,还有model-to-data、model-to-string等方法,都是先调用model-to-json,然后再利用系统的NSJSONSerialization、initWithData:encoding:进行转换

####### modelToJSONData

1
2
3
4
5
6
//先model-to-json,再json-to-data
- (NSData *)modelToJSONData {
id jsonObject = [self modelToJSONObject];
if (!jsonObject) return nil;
return [NSJSONSerialization dataWithJSONObject:jsonObject options:0 error:NULL];
}

####### modelToJSONString

1
2
3
4
5
6
//先model-to-data,再data-to-string
- (NSString *)modelToJSONString {
NSData *jsonData = [self modelToJSONData];
if (jsonData.length == 0) return nil;
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}

以上,解析json-to-model、model-to-json的转换过程解读完毕

四、一些宏的使用

1、NS_ASSUME_NONNULL_BEGIN、NS_ASSUME_NONNULL_END
我们可以给每个属性或每个方法都去指定 nullable 和 _nonnull,当一个类中,有的方法或属性给它指定了 nullable 和 _nonnull,其他方法又没有指定,编译器会爆警告。这时候可以全局使用NS_ASSUME_NONNULL_BEGIN、NS_ASSUME_NONNULL_END,然后再单独指定你要指定为__nullable的属性和方法。

2、#define force_inline inline attribute((always_inline))
attribute((always_inline))的意思是强制内联,
所有加了attribute((always_inline))的函数再被调用时不会被编译成函数调用而是直接扩展到调用函数体内

1
2
3
4
5
6
7
force_inline void a() {
print("hello");
}

void b(){
a();

b调用a函数的汇编代码不会是跳转到a执行,而是a函数的代码直接在b内成为b的一部分。
用force_inline代替 inline attribute((always_inline)),是因为比较方便。