YYModel
提供高性能的数据与model
互相转换的方法,并且提供了数据类型的适配和支持自定义属性名和键的映射,使用起来非常方便.
YYModel提供的接口
YYModel
的接口以分类的形式提供:
NSObject 分类
@interface NSObject (YYModel)
//使用json数据创建对象,json的类型可以使NSDictionary,NSData,NSString
+ (nullable instancetype)modelWithJSON:(id)json;
//使用NSDictionary 创建对象
+ (nullable instancetype)modelWithDictionary:(NSDictionary *)dictionary;
//使用json数据为属性赋值,json的类型可以使NSDictionary,NSData,NSString
- (BOOL)modelSetWithJSON:(id)json;
//使用NSDictionary为属性赋值
//当dic中的数据类型与属性的数据类型不匹配时,此方法会做一些适配,具体参考YYModel文档
- (BOOL)modelSetWithDictionary:(NSDictionary *)dic;
//使用自身创建一个json对象
//当方法的接收者是NSArray,NSDictionary,NSSet时,只是把内部的对象转换成json数据
- (nullable id)modelToJSONObject;
//使用自身创建一个json Data对象
//当方法的接收者是NSArray,NSDictionary,NSSet时,只是把内部的对象转换成json string
- (nullable NSData *)modelToJSONData;
//使用自身创建JSON 字符串数据
//当方法的接收者是NSArray,NSDictionary,NSSet时,只是把内部的对象转换成json string
- (nullable NSString *)modelToJSONString;
//拷贝自身
- (nullable id)modelCopy;
//归档方法
- (void)modelEncodeWithCoder:(NSCoder *)aCoder;
//解档方法
- (id)modelInitWithCoder:(NSCoder *)aDecoder;
//hash值
- (NSUInteger)modelHash;
//判断model是否相同
- (BOOL)modelIsEqual:(id)model;
//获取描述信息
- (NSString *)modelDescription;
@end
NSArray分类
@interface NSArray (YYModel)
//使用json array 实例化,json 格式类似 [{"name","Mary"},{name:"Joe"}],array中都是cls 对象
+ (nullable NSArray *)modelArrayWithClass:(Class)cls json:(id)json;
@end
NSDictionary分类
@interface NSDictionary (YYModel)
//使用json 实例化,json {"user1":{"name","Mary"}, "user2": {name:"Joe"}},json 中都是 cls对象
+ (nullable NSDictionary *)modelDictionaryWithClass:(Class)cls json:(id)json;
@end
YYModel 协议
YYModel 协议
定义了属性自定义映射的接口,以及转换过程的hook.
@protocol YYModel <NSObject>
@optional
/*
返回自定义的属性名称映射字典, 字典中的key 是属性名,
value是json数据中的key key path(e.g: a.b) , key array(e.g: @[@"a",@"a1"])
*/
+ (nullable NSDictionary<NSString *, id> *)modelCustomPropertyMapper;
//容器属性的泛型类映射器
+ (nullable NSDictionary<NSString *, id> *)modelContainerPropertyGenericClass;
//当要想要使用json数据返回自定义的类时使用此方法返回自定义的类型
+ (nullable Class)modelCustomClassForDictionary:(NSDictionary *)dictionary;
//在映射过程中忽略的属性集合,返回nil 忽略这个设置
+ (nullable NSArray<NSString *> *)modelPropertyBlacklist;
//如果属性名不在白名单中,在映射过程中会被忽略,返回nil 忽略这个设置
+ (nullable NSArray<NSString *> *)modelPropertyWhitelist;
//如果实现了这个方法,这个方法将在模型转换之前被调用
- (NSDictionary *)modelCustomWillTransformFromDictionary:(NSDictionary *)dic;
/*
实现这个方法来额外处理json-to-model过程,这个方法在
`+modelWithJSON:`, `+modelWithDictionary:`, `-modelSetWithJSON:` and `-modelSetWithDictionary:`.之后调用
验证model对象,返回YESmodel对象有效,返回NO忽略model对象
*/
- (BOOL)modelCustomTransformFromDictionary:(NSDictionary *)dic;
/*
实现这个方法来额外处理model-to-json过程,在`-modelToJSONObject` and `-modelToJSONString` 之后调用
来验证NSDictionary,返回YES. model有效,返回model有效,返回NOmodel被忽略
*/
- (BOOL)modelCustomTransformToDictionary:(NSMutableDictionary *)dic;
@end
json-to-model
+ (instancetype)modelWithJSON:(id)json {
//将json 转换为NSDictionary
NSDictionary *dic = [self _yy_dictionaryWithJSON:json];
//使用NSDictionary进行实例化
return [self modelWithDictionary:dic];
}
+ (instancetype)modelWithDictionary:(NSDictionary *)dictionary {
//参数合理性判断
if (!dictionary || dictionary == (id)kCFNull) return nil;
if (![dictionary isKindOfClass:[NSDictionary class]]) return nil;
//获取当前类
Class cls = [self class];
//使用类对象创建 _YYModelMeta,__YYModelMeta是对当前类信息的封装
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:cls];
if (modelMeta->_hasCustomClassFromDictionary) {
//当前类实现了 modelCustomClassForDictionary:方法
cls = [cls modelCustomClassForDictionary:dictionary] ?: cls;
}
//创建实例
NSObject *one = [cls new];
//使用NSDictionary为属性赋值,赋值成功则返回对象
if ([one modelSetWithDictionary:dictionary]) return one;
return nil;
}
从modelWithDictionary:
源码可以看到,去逻辑流程是首先获取当前类的信息,创建当前类实例,为当前类实例属性赋值,返回当前实例.
接下来看看_YYModelMeta
中都有些什么:
_YYModelMeta
/// 类信息的抽象
@interface _YYModelMeta : NSObject {
@package
//类的信息
YYClassInfo *_classInfo;
//key和key path 映射的属性信息字典,value是_YYModelPropertyMeta类型
NSDictionary *_mapper;
//model中所有的属性信息
NSArray *_allPropertyMetas;
//所有key path 映射的属性信息
NSArray *_keyPathPropertyMetas;
// 所有的 映射到多个键的属性信息
NSArray *_multiKeysPropertyMetas;
//_mapper.count.
NSUInteger _keyMappedCount;
//model类的类型
YYEncodingNSType _nsType;
//是否实现了`- modelCustomWillTransformFromDictionary:`方法
BOOL _hasCustomWillTransformFromDictionary;
//时候实现了`-modelCustomTransformFromDictionary:`方法
BOOL _hasCustomTransformFromDictionary;
//是否实现了-modelCustomTransformToDictionary:方法
BOOL _hasCustomTransformToDictionary;
//是否实现了-modelCustomClassForDictionary:方法
BOOL _hasCustomClassFromDictionary;
}
@end
创建_YYModelMeta
+ (instancetype)metaWithClass:(Class)cls {
if (!cls) return nil;
//全局缓存
static CFMutableDictionaryRef cache;
static dispatch_once_t onceToken;
//全局锁
static dispatch_semaphore_t lock;
dispatch_once(&onceToken, ^{
cache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
lock = dispatch_semaphore_create(1);
});
//加锁
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
//使用cls参数从缓存中取类信息
_YYModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls));
dispatch_semaphore_signal(lock);
//缓存中不存在 或者 类信息需要更新时
if (!meta || meta->_classInfo.needUpdate) {
//重新创建类信息描述
meta = [[_YYModelMeta alloc] initWithClass:cls];
if (meta) {
//线程安全地添加到缓存中
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta));
dispatch_semaphore_signal(lock);
}
}
return meta;
}
- (instancetype)initWithClass:(Class)cls {
//创建类对象的信息
YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls];
if (!classInfo) return nil;
self = [super init];
// Get black list
//获取黑名单属性名数组
NSSet *blacklist = nil;
if ([cls respondsToSelector:@selector(modelPropertyBlacklist)]) {
NSArray *properties = [(id<YYModel>)cls modelPropertyBlacklist];
if (properties) {
blacklist = [NSSet setWithArray:properties];
}
}
// Get white list
//获取白名单属性数组
NSSet *whitelist = nil;
if ([cls respondsToSelector:@selector(modelPropertyWhitelist)]) {
NSArray *properties = [(id<YYModel>)cls modelPropertyWhitelist];
if (properties) {
whitelist = [NSSet setWithArray:properties];
}
}
// Get container property's generic class
// 获取容器属性中的对象类型映射字典,最终得到类似 {@"key":Class} 的字典
NSDictionary *genericMapper = nil;
if ([cls respondsToSelector:@selector(modelContainerPropertyGenericClass)]) {
//原始的映射信息
genericMapper = [(id<YYModel>)cls modelContainerPropertyGenericClass];
//将 genericMapper中的所有的valuev转化为 Class
if (genericMapper) {
NSMutableDictionary *tmp = [NSMutableDictionary new];
[genericMapper enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if (![key isKindOfClass:[NSString class]]) return;
Class meta = object_getClass(obj);
if (!meta) return;
if (class_isMetaClass(meta)) {
tmp[key] = obj;
} else if ([obj isKindOfClass:[NSString class]]) {
Class cls = NSClassFromString(obj);
if (cls) {
tmp[key] = cls;
}
}
}];
genericMapper = tmp;
}
}
// Create all property metas.
// 获取所有的属性信息
NSMutableDictionary *allPropertyMetas = [NSMutableDictionary new];
YYClassInfo *curClassInfo = classInfo;
//递归的解析,忽略根类(NSObject/NSProxy),目的获取类的所有属性
while (curClassInfo && curClassInfo.superCls != nil) { // recursive parse super class, but ignore root class (NSObject/NSProxy)
//遍历 YYClassInfo.propertyInfos中所有的 类属性信息
for (YYClassPropertyInfo *propertyInfo in curClassInfo.propertyInfos.allValues) {
if (!propertyInfo.name) continue;
//跳过黑名单中的属性
if (blacklist && [blacklist containsObject:propertyInfo.name]) continue;
if (whitelist && ![whitelist containsObject:propertyInfo.name]) continue;
//创建 _YYModelPropertyMeta 属性信息对象
_YYModelPropertyMeta *meta = [_YYModelPropertyMeta metaWithClassInfo:classInfo
propertyInfo:propertyInfo
generic:genericMapper[propertyInfo.name]];
//对meta的关键属性进行合理性判断,不合理直接跳过
if (!meta || !meta->_name) continue;
if (!meta->_getter || !meta->_setter) continue;
if (allPropertyMetas[meta->_name]) continue;
//将属性信息放到 allPropertyMetas中 以 属性名称为 key
allPropertyMetas[meta->_name] = meta;
}
//指向父类
curClassInfo = curClassInfo.superClassInfo;
}
//保存allPropertyMetas
if (allPropertyMetas.count) _allPropertyMetas = allPropertyMetas.allValues.copy;
// create mapper
//创建包含所有的map
NSMutableDictionary *mapper = [NSMutableDictionary new];
//创建使用keypath映射的属性数组
NSMutableArray *keyPathPropertyMetas = [NSMutableArray new];
//创建使用多个keyo映射的属性数组
NSMutableArray *multiKeysPropertyMetas = [NSMutableArray new];
//当类实现了modelCustomPropertyMapper 自定义属性名方法名时
if ([cls respondsToSelector:@selector(modelCustomPropertyMapper)]) {
//获取自定义属性名方法名字典
NSDictionary *customMapper = [(id <YYModel>)cls modelCustomPropertyMapper];
//遍历所有key : value ,为 _YYModelPropertyMeta赋值key映射信息
[customMapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyName, NSString *mappedToKey, BOOL *stop) {
//使用属性名称从 所有的属性信息字典中获取 属性信息
_YYModelPropertyMeta *propertyMeta = allPropertyMetas[propertyName];
//获取失败直接跳过
if (!propertyMeta) return;
//获取成功首先移除
[allPropertyMetas removeObjectForKey:propertyName];
//key or keypath 映射的情况
if ([mappedToKey isKindOfClass:[NSString class]]) {
if (mappedToKey.length == 0) return;
//保存 映射的key
propertyMeta->_mappedToKey = mappedToKey;
//将keyPath转换成 key的数组
NSArray *keyPath = [mappedToKey componentsSeparatedByString:@"."];
for (NSString *onePath in keyPath) {
if (onePath.length == 0) {
NSMutableArray *tmp = keyPath.mutableCopy;
[tmp removeObject:@""];
keyPath = tmp;
break;
}
}
//key path映射
if (keyPath.count > 1) {
//key path的转化数组
propertyMeta->_mappedToKeyPath = keyPath;
//向keypath 映射数组中添加 该属性信息
[keyPathPropertyMetas addObject:propertyMeta];
}
//看看是否有多个属性映射到相同的key,如果有则将其用_next引用构成链表
propertyMeta->_next = mapper[mappedToKey] ?: nil;
//将映射后的key 与 属性信息做映射 (此时key是没有经过处理的)
mapper[mappedToKey] = propertyMeta;
}
//映射为多key的情况
else if ([mappedToKey isKindOfClass:[NSArray class]]) {
NSMutableArray *mappedToKeyArray = [NSMutableArray new];
//遍历key数组
for (NSString *oneKey in ((NSArray *)mappedToKey)) {
//合理性判断
if (![oneKey isKindOfClass:[NSString class]]) continue;
if (oneKey.length == 0) continue;
//处理其中一个key是 key path的的情况
NSArray *keyPath = [oneKey componentsSeparatedByString:@"."];
if (keyPath.count > 1) {
//将某一个keypath转换成 keypathArr ,添加到 mappedToKeyArray
[mappedToKeyArray addObject:keyPath];
} else {
[mappedToKeyArray addObject:oneKey];
}
//没有设置过属性信息的映射key时,设置_mappedToKey 和 _mappedToKeyPath
if (!propertyMeta->_mappedToKey) {
propertyMeta->_mappedToKey = oneKey;
propertyMeta->_mappedToKeyPath = keyPath.count > 1 ? keyPath : nil;
}
}
if (!propertyMeta->_mappedToKey) return;
//保存处理后的mappedToKeyArray
propertyMeta->_mappedToKeyArray = mappedToKeyArray;
//将 propertyMeta 添加到 multiKeysPropertyMetas
[multiKeysPropertyMetas addObject:propertyMeta];
//看看是否有多个属性映射到相同的key,如果有则将其用_next引用构成链表
propertyMeta->_next = mapper[mappedToKey] ?: nil;
//将映射后的key 与 属性信息做映射 (此时key是没有经过处理的)
mapper[mappedToKey] = propertyMeta;
}
}];
}
//遍历处理没有被 modelCustomPropertyMapper 包含的 剩下的属性
[allPropertyMetas enumerateKeysAndObjectsUsingBlock:^(NSString *name, _YYModelPropertyMeta *propertyMeta, BOOL *stop) {
//重新设置 _mappedToKey为属性名称
propertyMeta->_mappedToKey = name;
//看看是否有多个属性映射到相同的key,如果有则将其用_next引用构成链表
propertyMeta->_next = mapper[name] ?: nil;
//在mapper中做映射
mapper[name] = propertyMeta;
}];
//保存信息
if (mapper.count) _mapper = mapper;
if (keyPathPropertyMetas) _keyPathPropertyMetas = keyPathPropertyMetas;
if (multiKeysPropertyMetas) _multiKeysPropertyMetas = multiKeysPropertyMetas;
//保存类对象信息
_classInfo = classInfo;
_keyMappedCount = _allPropertyMetas.count;
//保存类型信息
_nsType = YYClassGetNSType(cls);
//保存YYModel协议方法实现信息
_hasCustomWillTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomWillTransformFromDictionary:)]);
_hasCustomTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformFromDictionary:)]);
_hasCustomTransformToDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformToDictionary:)]);
_hasCustomClassFromDictionary = ([cls respondsToSelector:@selector(modelCustomClassForDictionary:)]);
return self;
}
这里需要总结下:
_YYModelMeta
包含一个类的所有键值映射信息信息(每一个属性用_YYModelPropertyMeta
抽象)和类的信息YYClassInfo
.- 所有键值与
_YYModelPropertyMeta
映射信息保存_mapper
字典中,_mapper
中的key 可以是属性名称,映射过后的key, key array.- 映射为
keyPath
的所有属性信息保存在_keyPathPropertyMetas
数组中存储- 映射为多个key的所有属性信息保存在
_multiKeysPropertyMetas
数组中存储- _YYModelMeta 被缓存到了内存中.
YYClassInfo
接下来我们来看看YYClassInfo
里面都有什么
@interface YYClassInfo : NSObject
//当前类对象
@property (nonatomic, assign, readonly) Class cls;
//父类对象
@property (nullable, nonatomic, assign, readonly) Class superCls;
//元类对象
@property (nullable, nonatomic, assign, readonly) Class metaCls;
//当前类是否为元类
@property (nonatomic, readonly) BOOL isMeta;
//类的名称
@property (nonatomic, strong, readonly) NSString *name;
//父类的信息
@property (nullable, nonatomic, strong, readonly) YYClassInfo *superClassInfo;
//实例成员字典
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassIvarInfo *> *ivarInfos;
//方法字典
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassMethodInfo *> *methodInfos;
//属性字典
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassPropertyInfo *> *propertyInfos;
//当用runtime 给类添加了属性或者方法,应该调用和这个方法刷新类信息
- (void)setNeedUpdate;
//是否需要更新当前类信息
- (BOOL)needUpdate;
//使用类对象初始化
+ (nullable instancetype)classInfoWithClass:(Class)cls;
//使用类名进行初始化
+ (nullable instancetype)classInfoWithClassName:(NSString *)className;
@end
创建YYClassInfo
+ (instancetype)classInfoWithClass:(Class)cls {
if (!cls) return nil;
//类缓存
static CFMutableDictionaryRef classCache;
//元类缓存
static CFMutableDictionaryRef metaCache;
static dispatch_once_t onceToken;
//全局锁
static dispatch_semaphore_t lock;
dispatch_once(&onceToken, ^{
classCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
metaCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
lock = dispatch_semaphore_create(1);
});
//加锁
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
YYClassInfo *info = CFDictionaryGetValue(class_isMetaClass(cls) ? metaCache : classCache, (__bridge const void *)(cls));
//是否需要更新
if (info && info->_needUpdate) {
//调用更新方法
[info _update];
}
//解锁
dispatch_semaphore_signal(lock);
//缓存中不存在
if (!info) {
//调用实例方法创建
info = [[YYClassInfo alloc] initWithClass:cls];
if (info) {
//线程安全地加入缓存
dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
CFDictionarySetValue(info.isMeta ? metaCache : classCache, (__bridge const void *)(cls), (__bridge const void *)(info));
dispatch_semaphore_signal(lock);
}
}
return info;
}
- (instancetype)initWithClass:(Class)cls {
if (!cls) return nil;
self = [super init];
//保存当前类对象
_cls = cls;
//获取父类对象
_superCls = class_getSuperclass(cls);
//获取是否为元类
_isMeta = class_isMetaClass(cls);
if (!_isMeta) {
_metaCls = objc_getMetaClass(class_getName(cls));
}
//保存类的名称
_name = NSStringFromClass(cls);
//调用私有更新方法
[self _update];
//实例化父类信息
_superClassInfo = [self.class classInfoWithClass:_superCls];
return self;
}
- (void)_update {
//清空实例成员信息
_ivarInfos = nil;
//清空方法信息
_methodInfos = nil;
//清空属性信息
_propertyInfos = nil;
Class cls = self.cls;
unsigned int methodCount = 0;
//获取当前类所有方法
Method *methods = class_copyMethodList(cls, &methodCount);
if (methods) {
NSMutableDictionary *methodInfos = [NSMutableDictionary new];
_methodInfos = methodInfos;
//遍历所有方法
for (unsigned int i = 0; i < methodCount; i++) {
//创建方法信息抽象对象 YYClassMethodInfo
YYClassMethodInfo *info = [[YYClassMethodInfo alloc] initWithMethod:methods[i]];
//将方法信息对象抽象放到 methodInfos 字典中,方法名称为key
if (info.name) methodInfos[info.name] = info;
}
//释放资源
free(methods);
}
unsigned int propertyCount = 0;
//获取当前类所有属性
objc_property_t *properties = class_copyPropertyList(cls, &propertyCount);
if (properties) {
NSMutableDictionary *propertyInfos = [NSMutableDictionary new];
_propertyInfos = propertyInfos;
//遍历当前类所有属性
for (unsigned int i = 0; i < propertyCount; i++) {
//创建属性信息抽象对象
YYClassPropertyInfo *info = [[YYClassPropertyInfo alloc] initWithProperty:properties[i]];
//将属性信息对象放到 _propertyInfos 字典中,属性名称为key
if (info.name) propertyInfos[info.name] = info;
}
//释放资源
free(properties);
}
unsigned int ivarCount = 0;
//获取所有实例成员
Ivar *ivars = class_copyIvarList(cls, &ivarCount);
if (ivars) {
NSMutableDictionary *ivarInfos = [NSMutableDictionary new];
_ivarInfos = ivarInfos;
//遍历所有实例成员
for (unsigned int i = 0; i < ivarCount; i++) {
//创建实例成员信息抽象对象
YYClassIvarInfo *info = [[YYClassIvarInfo alloc] initWithIvar:ivars[i]];
//将实例成员信息抽象对象放到 _ivarInfos字典中, 实例成员名称为key
if (info.name) ivarInfos[info.name] = info;
}
//释放资源
free(ivars);
}
//如果不存在实例成员,则设置_ivarInfos默认值
if (!_ivarInfos) _ivarInfos = @{};
//如果不存在方法,则设置_methodInfos默认值
if (!_methodInfos) _methodInfos = @{};
//如果不存在属性,则设置_propertyInfos默认值
if (!_propertyInfos) _propertyInfos = @{};
//此时已经更新为最新,标记NO
_needUpdate = NO;
}
方法信息 YYClassMethodInfo
@interface YYClassMethodInfo : NSObject
//方法
@property (nonatomic, assign, readonly) Method method;
//方法名称
@property (nonatomic, strong, readonly) NSString *name;
//selector
@property (nonatomic, assign, readonly) SEL sel;
//IMP
@property (nonatomic, assign, readonly) IMP imp;
//方法类型编码值,详情可参考官方文档
@property (nonatomic, strong, readonly) NSString *typeEncoding;
//方法返回值的类型编码 ,详情可参考官方文档
@property (nonatomic, strong, readonly) NSString *returnTypeEncoding;
//方法参数的类型编码,详情可参考官方文档
@property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *argumentTypeEncodings; ///< array of arguments' type
//使用runtime 类型 Method 初始化
- (instancetype)initWithMethod:(Method)method;
@end
关于类型编码的官方文档: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html
创建YYClassMethodInfo
- (instancetype)initWithMethod:(Method)method {
if (!method) return nil;
self = [super init];
//保存method
_method = method;
//获取SEL 并保存
_sel = method_getName(method);
//获取方法实现指针并保存
_imp = method_getImplementation(method);
//获取方法名称并保存
const char *name = sel_getName(_sel);
if (name) {
_name = [NSString stringWithUTF8String:name];
}
//获取方法类型编码并保存
const char *typeEncoding = method_getTypeEncoding(method);
if (typeEncoding) {
_typeEncoding = [NSString stringWithUTF8String:typeEncoding];
}
//获取方法返回值类型并保存
char *returnType = method_copyReturnType(method);
if (returnType) {
_returnTypeEncoding = [NSString stringWithUTF8String:returnType];
//释放资源
free(returnType);
}
//获取方法参数个数
unsigned int argumentCount = method_getNumberOfArguments(method);
if (argumentCount > 0) {
NSMutableArray *argumentTypes = [NSMutableArray new];
//遍历方法参数
for (unsigned int i = 0; i < argumentCount; i++) {
//获取某一参数的类型编码
char *argumentType = method_copyArgumentType(method, i);
NSString *type = argumentType ? [NSString stringWithUTF8String:argumentType] : nil;
//添加到参数类型编码数组
[argumentTypes addObject:type ? type : @""];
//释放资源
if (argumentType) free(argumentType);
}
//保存参数类型编码数组
_argumentTypeEncodings = argumentTypes;
}
return self;
}
属性信息YYClassPropertyInfo
@interface YYClassPropertyInfo : NSObject
//runtime property
@property (nonatomic, assign, readonly) objc_property_t property;
//属性名称
@property (nonatomic, strong, readonly) NSString *name;
//属性类型编码 转化过的
@property (nonatomic, assign, readonly) YYEncodingType type;
// 属性编码值
@property (nonatomic, strong, readonly) NSString *typeEncoding;
// 实例变量名称
@property (nonatomic, strong, readonly) NSString *ivarName;
// 属性的类, 可以为空
@property (nullable, nonatomic, assign, readonly) Class cls;
// 属性所继承的协议,可以为空
@property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *protocols;
// 属性所对应的getter方法的SEL
@property (nonatomic, assign, readonly) SEL getter;
// 属性所对应的setter方法的SEL
@property (nonatomic, assign, readonly) SEL setter;
//实例化方法
- (instancetype)initWithProperty:(objc_property_t)property;
@end
创建YYClassPropertyInfo
- (instancetype)initWithProperty:(objc_property_t)property {
//参数合理性判断
if (!property) return nil;
//调用父类初始化方法
self = [super init];
//保存 objc_property_t
_property = property;
//获取属性名并保存
const char *name = property_getName(property);
if (name) {
_name = [NSString stringWithUTF8String:name];
}
YYEncodingType type = 0;
unsigned int attrCount;
//获取属性的信息列表
objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount);
//遍历属性的信息列表
for (unsigned int i = 0; i < attrCount; i++) {
switch (attrs[i].name[0]) {
case 'T': { // Type encoding
if (attrs[i].value) {
_typeEncoding = [NSString stringWithUTF8String:attrs[i].value];
//转换为YYEncodingType类型
type = YYEncodingGetType(attrs[i].value);
//当属性的类型是对象时
if ((type & YYEncodingTypeMask) == YYEncodingTypeObject && _typeEncoding.length) {
NSScanner *scanner = [NSScanner scannerWithString:_typeEncoding];
//判断类型编码字符串中有没有 @" 字符串
if (![scanner scanString:@"@\"" intoString:NULL]) continue;
NSString *clsName = nil;
//扫描的 " 或者 <
if ([scanner scanUpToCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString:@"\"<"] intoString:&clsName]) {
//获取当属性的类
if (clsName.length) _cls = objc_getClass(clsName.UTF8String);
}
// 编码类型字符串中, 每个< > 之间就是协议的名称
NSMutableArray *protocols = nil;
while ([scanner scanString:@"<" intoString:NULL]) {
NSString* protocol = nil;
if ([scanner scanUpToString:@">" intoString: &protocol]) {
if (protocol.length) {
if (!protocols) protocols = [NSMutableArray new];
//将每个协议名称添加到属性数组中
[protocols addObject:protocol];
}
}
[scanner scanString:@">" intoString:NULL];
}
//保存协议名称数组
_protocols = protocols;
}
}
} break;
case 'V': { // Instance variable
if (attrs[i].value) {
//保存实例变量名
_ivarName = [NSString stringWithUTF8String:attrs[i].value];
}
} break;
case 'R': {
//只读属性
type |= YYEncodingTypePropertyReadonly;
} break;
case 'C': {
// 内存语义是 copy的属性
type |= YYEncodingTypePropertyCopy;
} break;
case '&': {
// strong
type |= YYEncodingTypePropertyRetain;
} break;
case 'N': {
// nonatomic
type |= YYEncodingTypePropertyNonatomic;
} break;
case 'D': {
// 属性声明了 @dynamic
type |= YYEncodingTypePropertyDynamic;
} break;
case 'W': {
// weak
type |= YYEncodingTypePropertyWeak;
} break;
case 'G': {
//设置了自定义getter名称
type |= YYEncodingTypePropertyCustomGetter;
if (attrs[i].value) {
//保存自定义getter名称
_getter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
}
} break;
case 'S': { //设置了自定义 setter名称
type |= YYEncodingTypePropertyCustomSetter;
if (attrs[i].value) {
//保存自定义setter名称
_setter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
}
} // break; commented for code coverage in next line
default: break;
}
}
//释放资源
if (attrs) {
free(attrs);
attrs = NULL;
}
//保存 YYEncodingType
_type = type;
if (_name.length) {
//当没有设置自定义 getter 名称时
if (!_getter) {
//为_getter设置默认getter方法SEL
_getter = NSSelectorFromString(_name);
}
//当没有设置自定义 setter 名称时
if (!_setter) {
//设置_setter 为 默认setter方法SEL
_setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [_name substringToIndex:1].uppercaseString, [_name substringFromIndex:1]]);
}
}
return self;
}
实例成员信息YYClassIvarInfo
@interface YYClassIvarInfo : NSObject
// Ivar 结构体类型
@property (nonatomic, assign, readonly) Ivar ivar;
//实例成员的名称
@property (nonatomic, strong, readonly) NSString *name;
//成员所在的偏移量
@property (nonatomic, assign, readonly) ptrdiff_t offset;
// 成员的类型编码
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< Ivar's type encoding
// 转化过后的YY类型编码
@property (nonatomic, assign, readonly) YYEncodingType type; ///< Ivar's type
//实例化方法
- (instancetype)initWithIvar:(Ivar)ivar;
@end
创建 YYClassIvarInfo
- (instancetype)initWithIvar:(Ivar)ivar {
//参数合理性判断
if (!ivar) return nil;
//调用super 初始化方法
self = [super init];
//保存ivar结构体
_ivar = ivar;
//获取属性名称
const char *name = ivar_getName(ivar);
if (name) {
//属性名称不为空则保存
_name = [NSString stringWithUTF8String:name];
}
//保存实例成员的偏移量
_offset = ivar_getOffset(ivar);
//获取类型编码
const char *typeEncoding = ivar_getTypeEncoding(ivar);
if (typeEncoding) {
//类型编码不为空则保存
_typeEncoding = [NSString stringWithUTF8String:typeEncoding];
//保存转化过后的YYEncodingType
_type = YYEncodingGetType(typeEncoding);
}
return self;
}
属性信息的模型对象 _YYModelPropertyMeta
@interface _YYModelPropertyMeta : NSObject {
@package
//属性名称
NSString *_name;
//类型编码
YYEncodingType _type;
//属性的Foundation type
YYEncodingNSType _nsType;
//是否为c 数字类型
BOOL _isCNumber;
//属性的类 ,可以为空,因为属性不一定是对象
Class _cls;
//容器中的泛型类 ,可以为空
Class _genericCls;
//getter 方法 SEL ,可以为空
SEL _getter;
//setter 方法 SEL ,可以为空
SEL _setter;
//是否支持KVO
BOOL _isKVCCompatible;
// 是否 Struct 结构体支持 归档/ 解档
BOOL _isStructAvailableForKeyedArchiver;
//是否 属性的类或者泛型的类是否实现了+modelCustomClassForDictionary:
BOOL _hasCustomClassFromDictionary;
//映射过后的key
NSString *_mappedToKey;
//映射过后的key path
NSArray *_mappedToKeyPath;
//映射过后的key array
NSArray *_mappedToKeyArray;
//属性信息
YYClassPropertyInfo *_info;
//相同key属性的指针
_YYModelPropertyMeta *_next;
}
@end
创建_YYModelPropertyMeta
+ (instancetype)metaWithClassInfo:(YYClassInfo *)classInfo
propertyInfo:(YYClassPropertyInfo *)propertyInfo
generic:(Class)generic {
// support pseudo generic class with protocol name
//支持集合中的泛型为协议
if (!generic && propertyInfo.protocols) {
for (NSString *protocol in propertyInfo.protocols) {
Class cls = objc_getClass(protocol.UTF8String);
if (cls) {
generic = cls;
break;
}
}
}
//创建 _YYModelPropertyMeta
_YYModelPropertyMeta *meta = [self new];
//赋值属性名称
meta->_name = propertyInfo.name;
//赋值属性类型编码
meta->_type = propertyInfo.type;
//赋值属性信息
meta->_info = propertyInfo;
//赋值泛型类
meta->_genericCls = generic;
//属性为对象类型
if ((meta->_type & YYEncodingTypeMask) == YYEncodingTypeObject) {
//获取具体的对象类型
meta->_nsType = YYClassGetNSType(propertyInfo.cls);
} else {
//当前属性不是对象类型
//判断是否为 是不是 c 语言数字类型
meta->_isCNumber = YYEncodingTypeIsCNumber(meta->_type);
}
//属性为 结构体类型
if ((meta->_type & YYEncodingTypeMask) == YYEncodingTypeStruct) {
/*
It seems that NSKeyedUnarchiver cannot decode NSValue except these structs:
*/
static NSSet *types = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSMutableSet *set = [NSMutableSet new];
// 32 bit
[set addObject:@"{CGSize=ff}"];
[set addObject:@"{CGPoint=ff}"];
[set addObject:@"{CGRect={CGPoint=ff}{CGSize=ff}}"];
[set addObject:@"{CGAffineTransform=ffffff}"];
[set addObject:@"{UIEdgeInsets=ffff}"];
[set addObject:@"{UIOffset=ff}"];
// 64 bit
[set addObject:@"{CGSize=dd}"];
[set addObject:@"{CGPoint=dd}"];
[set addObject:@"{CGRect={CGPoint=dd}{CGSize=dd}}"];
[set addObject:@"{CGAffineTransform=dddddd}"];
[set addObject:@"{UIEdgeInsets=dddd}"];
[set addObject:@"{UIOffset=dd}"];
types = set;
});
//只有系统的结构体类型支持归档和解档
if ([types containsObject:propertyInfo.typeEncoding]) {
meta->_isStructAvailableForKeyedArchiver = YES;
}
}
//保存类信息
meta->_cls = propertyInfo.cls;
//获取 自定义的 转化类的信息
if (generic) {
meta->_hasCustomClassFromDictionary = [generic respondsToSelector:@selector(modelCustomClassForDictionary:)];
} else if (meta->_cls && meta->_nsType == YYEncodingTypeNSUnknown) {
meta->_hasCustomClassFromDictionary = [meta->_cls respondsToSelector:@selector(modelCustomClassForDictionary:)];
}
if (propertyInfo.getter) {
//在属性的类能响应属性的getter方法时 保存 getter SEL
if ([classInfo.cls instancesRespondToSelector:propertyInfo.getter]) {
meta->_getter = propertyInfo.getter;
}
}
if (propertyInfo.setter) {
//在属性的类能响应属性的setter 方法时 保存 setter SEL
if ([classInfo.cls instancesRespondToSelector:propertyInfo.setter]) {
meta->_setter = propertyInfo.setter;
}
}
//getter 和 setter 保存成功时
if (meta->_getter && meta->_setter) {
/*
KVC invalid type:
long double
pointer (such as SEL/CoreFoundation object)
*/
switch (meta->_type & YYEncodingTypeMask) {
case YYEncodingTypeBool:
case YYEncodingTypeInt8:
case YYEncodingTypeUInt8:
case YYEncodingTypeInt16:
case YYEncodingTypeUInt16:
case YYEncodingTypeInt32:
case YYEncodingTypeUInt32:
case YYEncodingTypeInt64:
case YYEncodingTypeUInt64:
case YYEncodingTypeFloat:
case YYEncodingTypeDouble:
case YYEncodingTypeObject:
case YYEncodingTypeClass:
case YYEncodingTypeBlock:
case YYEncodingTypeStruct:
case YYEncodingTypeUnion: {
//以上的类型支持KVO
meta->_isKVCCompatible = YES;
} break;
default: break;
}
}
//返回
return meta;
}
至此,对类信息,属性信息,方法信息的抽象部分就都看完了,下面来接着看在具体的 json -to-model
过程中如何为属性赋值的.
为属性赋值
- (BOOL)modelSetWithDictionary:(NSDictionary *)dic {
//参数合理性判断
if (!dic || dic == (id)kCFNull) return NO;
if (![dic isKindOfClass:[NSDictionary class]]) return NO;
//创建 _YYModelMeta对象
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:object_getClass(self)];
//没有属性映射则直接返回失败
if (modelMeta->_keyMappedCount == 0) return NO;
//如果模型对象实现了 modelCustomWillTransformFromDictionary:方法
if (modelMeta->_hasCustomWillTransformFromDictionary) {
//在进行转换前 调用 modelCustomWillTransformFromDictionary
dic = [((id<YYModel>)self) modelCustomWillTransformFromDictionary:dic];
if (![dic isKindOfClass:[NSDictionary class]]) return NO;
}
//创建 ModelSetContext结构体
ModelSetContext context = {0};
context.modelMeta = (__bridge void *)(modelMeta);
context.model = (__bridge void *)(self);
context.dictionary = (__bridge void *)(dic);
//模型对象自定义了属性映射属相超过了数据value的个数
if (modelMeta->_keyMappedCount >= CFDictionaryGetCount((CFDictionaryRef)dic)) {
//调用ModelSetWithDictionaryFunction赋值
CFDictionaryApplyFunction((CFDictionaryRef)dic, ModelSetWithDictionaryFunction, &context);
if (modelMeta->_keyPathPropertyMetas) {
//调用 ModelSetWithPropertyMetaArrayFunction 为所有的 keyPath映射属性赋值
CFArrayApplyFunction((CFArrayRef)modelMeta->_keyPathPropertyMetas,
CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_keyPathPropertyMetas)),
ModelSetWithPropertyMetaArrayFunction,
&context);
}
if (modelMeta->_multiKeysPropertyMetas) {
// 调动 ModelSetWithPropertyMetaArrayFunction 为所有的 multikey 映射属性赋值
CFArrayApplyFunction((CFArrayRef)modelMeta->_multiKeysPropertyMetas,
CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_multiKeysPropertyMetas)),
ModelSetWithPropertyMetaArrayFunction,
&context);
}
} else { //模型对象自定义了属性映射属相少于数据value的个数
//调用 ModelSetWithPropertyMetaArrayFunction 为属性赋值
CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,
CFRangeMake(0, modelMeta->_keyMappedCount),
ModelSetWithPropertyMetaArrayFunction,
&context);
}
//作为属性的对象实现了 modelCustomTransformFromDictionary:方法 则调用
if (modelMeta->_hasCustomTransformFromDictionary) {
return [((id<YYModel>)self) modelCustomTransformFromDictionary:dic];
}
//返回成功
return YES;
}
//为某一属性赋值
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);
//遍历所有具有相同key的属性,进行赋值
while (propertyMeta) {
//属性具有setter方法
if (propertyMeta->_setter) {
// 调用 ModelSetValueForProperty 为属性赋值
ModelSetValueForProperty(model, (__bridge __unsafe_unretained id)_value, propertyMeta);
}
propertyMeta = propertyMeta->_next;
};
}
static void ModelSetValueForProperty(__unsafe_unretained id model,
__unsafe_unretained id value,
__unsafe_unretained _YYModelPropertyMeta *meta) {
//解析属性类型,按类型执行真正的赋值操作
//属性是 c 数字类型
if (meta->_isCNumber) {
//json 数据中的value 转化为 NSNumber类型
NSNumber *num = YYNSNumberCreateFromID(value);
//为属性赋值num数据
ModelSetNumberToProperty(model, num, meta);
if (num) [num class]; // hold the number
} else if (meta->_nsType) { //属性是对象类型
if (value == (id)kCFNull) { //属性是nil 时
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
} else {
//属性非空,解析其具体的 Foundation 类型
switch (meta->_nsType) {
//属性类型为 NSString or NSMutableString
case YYEncodingTypeNSString:
case YYEncodingTypeNSMutableString: {
//value 类型是 NSString
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);
}
//value 类型是 NSNumber 需要将value转换为 具体的string类型(NSString or NSMutableString) 再赋值
} 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);
//value 类型是 NSData 需要将value转换为 具体的string类型(NSString or NSMutableString) 再赋值
} 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);
//value 类型是 NSURL 需要将value转换为 具体的string类型(NSString or NSMutableString) 再赋值
} 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);
// value 类型是 NSAttributedString 需要将value转换为 具体的string类型(NSString or NSMutableString) 再赋值
} 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: {
//属性类型是 NSNumber
if (meta->_nsType == YYEncodingTypeNSNumber) {
// value 类型是 NSNumber, 创建NSNumber赋值
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSNumberCreateFromID(value));
}
// 属性类型是 NSDecimalNumber
else if (meta->_nsType == YYEncodingTypeNSDecimalNumber) {
// value 类型是 NSDecimalNumber 与属性类型相同 直接赋值
if ([value isKindOfClass:[NSDecimalNumber class]]) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
}
// value 类型是 NSNumber 直接赋值 转化为 NSDecimalNumber 再赋值
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);
}
// value 类型是 NSString 转化为 NSDecimalNumber 再赋值
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
//属性 类型是 NSValue 并且 value 类型也是 NSValue 才赋值
if ([value isKindOfClass:[NSValue class]]) {
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
}
}
} break;
// 属性类型是 NSData or NSMutableData
case YYEncodingTypeNSData:
case YYEncodingTypeNSMutableData: {
//判断value具体类型 , 转化为 NSData or NSMutableData 赋值
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;
//属性类型是 NSDate
case YYEncodingTypeNSDate: {
//判断value具体类型 , 转化为 NSDate 赋值
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;
//属性类型是 NSURL
case YYEncodingTypeNSURL: {
//判断value具体类型 , 转化为 NSURL 赋值
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;
//属性类型是 NSArray or NSMutableArray
case YYEncodingTypeNSArray:
case YYEncodingTypeNSMutableArray: {
//属性指定了集合中的 类
if (meta->_genericCls) {
//value合理性转化
NSArray *valueArr = nil;
if ([value isKindOfClass:[NSArray class]]) valueArr = value;
else if ([value isKindOfClass:[NSSet class]]) valueArr = ((NSSet *)value).allObjects;
//value 合格
if (valueArr) {
NSMutableArray *objectArr = [NSMutableArray new];
// 遍历value 中的json 数据,并且把json数据转化为对象
for (id one in valueArr) {
// 当value 集合中的值是指定的类对象
if ([one isKindOfClass:meta->_genericCls]) {
//直接添加到对象数组中
[objectArr addObject:one];
}
// 当value 集合中的值是NSDictionary,这时说明没有指定 集合中的对象类型
else if ([one isKindOfClass:[NSDictionary class]]) {
Class cls = meta->_genericCls;
//实现了 modelCustomClassForDictionary:方法
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 {
//属性没有指定集合中的 类
//则解析value 类型,不对其元素进行任何处理, 转化为 正确的类型直接赋值
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;
//属性的类型 NSDictionary or NSMutableDictionary
case YYEncodingTypeNSDictionary:
case YYEncodingTypeNSMutableDictionary: {
//value 的类型是 NSDictionary
if ([value isKindOfClass:[NSDictionary class]]) {
//属性指定了集合中的 类
if (meta->_genericCls) {
NSMutableDictionary *dic = [NSMutableDictionary new];
//遍历value 中所有的键值对
[((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];
//将转化成功的对象放到临时 dic 中
if (newOne) dic[oneKey] = newOne;
}
}];
//赋值操作
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, dic);
} else {
//属性没有指定集合中的 类
//直接转化 value类型进行赋值
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;
// 属性类型是 NSSet or NSMutableSet
case YYEncodingTypeNSSet:
case YYEncodingTypeNSMutableSet: {
// value 合理性转化
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) {
// 集合中的数据 是指定的 类 则直接添加到set
if ([one isKindOfClass:meta->_genericCls]) {
[set addObject:one];
}
// 集合中的数据 是NSDictionary 则需要递归处理
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 {
//属性没有止境集合中的 类
//转化value 的类型进行赋值
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: {
if (isNull) {
// value 是nil 则直接赋值nil
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
} else if ([value isKindOfClass:meta->_cls] || !meta->_cls) {
// value 是 自定义的对象类型 则直接赋值
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)value);
} else if ([value isKindOfClass:[NSDictionary class]]) {
// value 是 NSDictionary 需要转化
NSObject *one = nil;
//先获取当前属性的值
if (meta->_getter) {
one = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
}
//当前属性存在则直接调用赋值方法更新数据
if (one) {
[one modelSetWithDictionary:value];
} else {
//获取属性的类
Class cls = meta->_cls;
//处理自定义
if (meta->_hasCustomClassFromDictionary) {
cls = [cls modelCustomClassForDictionary:value];
if (!cls) cls = meta->_genericCls; // for xcode code coverage
}
//实例化
one = [cls new];
//调用赋值方法为one赋值
[one modelSetWithDictionary:value];
//为当前属性赋值
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)one);
}
}
} break;
//属性的类型是 Class
case YYEncodingTypeClass: {
if (isNull) {
//value 为空时直接置空
((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)NULL);
} else {
Class cls = nil;
//value的类型是 NSString 转化为 Class 赋值
if ([value isKindOfClass:[NSString class]]) {
cls = NSClassFromString(value);
if (cls) {
((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)cls);
}
} else {
//尝试直接获取 class 成功则赋值
cls = object_getClass(value);
if (cls) {
if (class_isMetaClass(cls)) {
((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)value);
}
}
}
}
} break;
//属性的类型是 SEL
case YYEncodingTypeSEL: {
if (isNull) {
//value 为空时直接置空
((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)NULL);
}
//value 类型为 NSString时转化为 SEL赋值
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;
//属性类型是 block
case YYEncodingTypeBlock: {
if (isNull) {
//value 为空时直接置空
((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())NULL);
}
//value值类型是 block类型则赋值
else if ([value isKindOfClass:YYNSBlockClass()]) {
((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())value);
}
} break;
//属性的类型是 Struct or Union or C array
case YYEncodingTypeStruct:
case YYEncodingTypeUnion:
case YYEncodingTypeCArray: {
//当value的类型是 NSValue 才可赋值
if ([value isKindOfClass:[NSValue class]]) {
const char *valueType = ((NSValue *)value).objCType;
const char *metaType = meta->_info.typeEncoding.UTF8String;
//value中包装的数据是 objc 可以处理的
if (valueType && metaType && strcmp(valueType, metaType) == 0) {
[model setValue:value forKey:meta->_name];
}
}
} break;
//属性的类型是 指针 或者 char*
case YYEncodingTypePointer:
case YYEncodingTypeCString: {
if (isNull) {
//value 为空时直接置空
((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, (void *)NULL);
} else if ([value isKindOfClass:[NSValue class]]) {
NSValue *nsValue = value;
//是否可以转换类void *
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;
}
}
}
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);
//当前属性没有setter SEL 则直接返回
if (!propertyMeta->_setter) return;
id value = nil;
//属性映射了多key
if (propertyMeta->_mappedToKeyArray) {
//调用多key映射取值方法
value = YYValueForMultiKeys(dictionary, propertyMeta->_mappedToKeyArray);
}
//属性映射了 keypath
else if (propertyMeta->_mappedToKeyPath) {
//调用 keypath取值方法
value = YYValueForKeyPath(dictionary, propertyMeta->_mappedToKeyPath);
}
//属性映射了 自定义key
else {
value = [dictionary objectForKey:propertyMeta->_mappedToKey];
}
if (value) {
__unsafe_unretained id model = (__bridge id)(context->model);
//调用为属性赋值的方法
ModelSetValueForProperty(model, value, propertyMeta);
}
}
总结下json-to-model 过程:
- 在调用
modelWithJSON:
方法后,会使用当前消息接收者Class
,在缓存中获取_YYModelMeta
(_YYModelMeta
是对模型类信息的抽象).如果获取失败,会使用Class创建_YYModelMeta
,然后放入内存缓存.- 获取
_YYModelMeta
后,使用_YYModelMeta
为消息接收者的属性赋值,在这个赋值的过程中使用_YYModelMeta
中存储的属性信息(映射的key,setter,属性的类型等)和json数据的类型做适配.然后直接使用objc_msgSend
函数地址调动赋值过程,减少开销.
model-to-json
来看看模型转换到json的过程:
- (id)modelToJSONObject {
//调用递归转换函数获取json对象,传递自身实例
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) {
//model是 NSNull 实例,直接返回
if (!model || model == (id)kCFNull) return model;
//model是 NSString 实例 直接返回
if ([model isKindOfClass:[NSString class]]) return model;
//model 是 NSNumber实例 直接返回
if ([model isKindOfClass:[NSNumber class]]) return model;
//model 是 NSDictionary实例
if ([model isKindOfClass:[NSDictionary class]]) {
//model 是字典,并且可以转换为json data ,直接返回
if ([NSJSONSerialization isValidJSONObject:model]) return model;
NSMutableDictionary *newDic = [NSMutableDictionary new];
//遍历model 中的每个key value,把对应的value转换为 json对象
[((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是 NSSet 实例
if ([model isKindOfClass:[NSSet class]]) {
//转化为 数组
NSArray *array = ((NSSet *)model).allObjects;
//数组可以转化为有效的JSON data直接返回数组
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 {
//数组的元素是除NSString 和 NSNumber对象类型,递归地转化为JSON data
id jsonObj = ModelToJSONObjectRecursive(obj);
//转化成功添加到新数组中
if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
}
}
//返回新数组
return newArray;
}
//model是 NSArray 实例
if ([model isKindOfClass:[NSArray class]]) {
//数组可以转化为有效的JSON data直接返回数组
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 {
//数组的元素是除NSString 和 NSNumber对象类型,递归地转化为JSON data
id jsonObj = ModelToJSONObjectRecursive(obj);
//转化成功添加到新数组中
if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
}
}
//返回新数组
return newArray;
}
// NSURL 对象要转化为 NSString
if ([model isKindOfClass:[NSURL class]]) return ((NSURL *)model).absoluteString;
// NSAttributedString 要转化为 NSString
if ([model isKindOfClass:[NSAttributedString class]]) return ((NSAttributedString *)model).string;
// NSDate 要转化为 NSSString
if ([model isKindOfClass:[NSDate class]]) return [YYISODateFormatter() stringFromDate:(id)model];
// NSData 不可以放到json 中
if ([model isKindOfClass:[NSData class]]) return nil;
//获取模型类的信息 _YYModelMeta
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:[model class]];
//合理性判断
if (!modelMeta || modelMeta->_keyMappedCount == 0) return nil;
NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:64];
__unsafe_unretained NSMutableDictionary *dic = result; // avoid retain and release in block
//model的所有属性
[modelMeta->_mapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyMappedKey, _YYModelPropertyMeta *propertyMeta, BOOL *stop) {
//属性没有getter SEL 直接返回失败
if (!propertyMeta->_getter) return;
id value = nil;
//属性的类型是c 语言类型的数字
if (propertyMeta->_isCNumber) {
// 调用model的getter,并将得到的c类型的数字转换为NSNumber
value = ModelCreateNumberFromProperty(model, propertyMeta);
}
//属性的类型是 Foundation类型
else if (propertyMeta->_nsType) {
//调用getter 获取值
id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
// 递归地转化为json data
value = ModelToJSONObjectRecursive(v);
}
else {
switch (propertyMeta->_type & YYEncodingTypeMask) {
//属性的类型是自定义的类
case YYEncodingTypeObject: {
//调用getter 获取值
id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
// 递归地转化为json data
value = ModelToJSONObjectRecursive(v);
if (value == (id)kCFNull) value = nil;
} break;
//属性的类型是 类对象 Class
case YYEncodingTypeClass: {
//调用getter 获取值
Class v = ((Class (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
//直接将 Class 转化为NSString
value = v ? NSStringFromClass(v) : nil;
} break;
//属性的类型是 SEL
case YYEncodingTypeSEL: {
//调用getter 获取值
SEL v = ((SEL (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
//直接将 SEL 转化为NSString
value = v ? NSStringFromSelector(v) : nil;
} break;
default: break;
}
}
//转化失败,返回
if (!value) return;
//为JSON数据添加key value
//当属性是key path 映射时,需要构造到最内层字典才能赋值
if (propertyMeta->_mappedToKeyPath) {
NSMutableDictionary *superDic = dic;
NSMutableDictionary *subDic = nil;
//遍历key path 数组
for (NSUInteger i = 0, max = propertyMeta->_mappedToKeyPath.count; i < max; i++) {
NSString *key = propertyMeta->_mappedToKeyPath[i];
if (i + 1 == max) { // end
//最后一个直接用key赋值
if (!superDic[key]) superDic[key] = value;
break;
}
subDic = superDic[key];
//当前key已经设置过
if (subDic) {
if ([subDic isKindOfClass:[NSDictionary class]]) {
//赋值一下在赋值
subDic = subDic.mutableCopy;
superDic[key] = subDic;
} else {
//已经到了最内层NSDictionary
break;
}
} else { //当前key没有设置过
//创建NSDictionary
subDic = [NSMutableDictionary new];
//添加值
superDic[key] = subDic;
}
//指向下一层
superDic = subDic;
subDic = nil;
}
} else {
//直接为字典赋值
if (!dic[propertyMeta->_mappedToKey]) {
dic[propertyMeta->_mappedToKey] = value;
}
}
}];
//当前模型实现了 modelCustomTransformToDictionary:,调用通知外界
if (modelMeta->_hasCustomTransformToDictionary) {
BOOL suc = [((id<YYModel>)model) modelCustomTransformToDictionary:dic];
if (!suc) return nil;
}
//返回构造好的Dictionary
return result;
}
model-to-json
过程就是利用_YYModelMeta 中存储的模型属性信息构造NSDictionary
的过程, 在构造过程中使用_YYModelPropertyMeta
中存储的属性类型信息把属性值转化为能够放到NSDictionary
中的类型, 最后用_YYModelPropertyMeta中存储的key信息作为JOSN中的key进行赋值.
copy方法
由于 YYModel是以分类方法的形式提供结构,所以没有直接重写系统的copy
方法,而是提供了modelCopy
方法
//归档
- (id)modelCopy{
// 被拷贝对象 是nil 可以直接返回self
if (self == (id)kCFNull) return self;
// 获取当前对象类信息
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
// 是Fundation对象 直接调用 copy方法返回
if (modelMeta->_nsType) return [self copy];
//创建当前对象的新实例
NSObject *one = [self.class new];
//遍历所有属性,解析属性类型调用setter赋值
for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
if (!propertyMeta->_getter || !propertyMeta->_setter) continue;
if (propertyMeta->_isCNumber) {
switch (propertyMeta->_type & YYEncodingTypeMask) {
case YYEncodingTypeBool: {
bool num = ((bool (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
} break;
case YYEncodingTypeInt8:
case YYEncodingTypeUInt8: {
uint8_t num = ((bool (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
((void (*)(id, SEL, uint8_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
} break;
case YYEncodingTypeInt16:
case YYEncodingTypeUInt16: {
uint16_t num = ((uint16_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
((void (*)(id, SEL, uint16_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
} break;
case YYEncodingTypeInt32:
case YYEncodingTypeUInt32: {
uint32_t num = ((uint32_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
} break;
case YYEncodingTypeInt64:
case YYEncodingTypeUInt64: {
uint64_t num = ((uint64_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
} break;
case YYEncodingTypeFloat: {
float num = ((float (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
((void (*)(id, SEL, float))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
} break;
case YYEncodingTypeDouble: {
double num = ((double (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
((void (*)(id, SEL, double))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
} break;
case YYEncodingTypeLongDouble: {
long double num = ((long double (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
((void (*)(id, SEL, long double))(void *) objc_msgSend)((id)one, propertyMeta->_setter, num);
} // break; commented for code coverage in next line
default: break;
}
} else {
switch (propertyMeta->_type & YYEncodingTypeMask) {
case YYEncodingTypeObject:
case YYEncodingTypeClass:
case YYEncodingTypeBlock: {
id value = ((id (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)one, propertyMeta->_setter, value);
} break;
case YYEncodingTypeSEL:
case YYEncodingTypePointer:
case YYEncodingTypeCString: {
size_t value = ((size_t (*)(id, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_getter);
((void (*)(id, SEL, size_t))(void *) objc_msgSend)((id)one, propertyMeta->_setter, value);
} break;
case YYEncodingTypeStruct:
case YYEncodingTypeUnion: {
@try {
NSValue *value = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
if (value) {
[one setValue:value forKey:propertyMeta->_name];
}
} @catch (NSException *exception) {}
} // break; commented for code coverage in next line
default: break;
}
}
}
return one;
}
归档/解档
- (void)modelEncodeWithCoder:(NSCoder *)aCoder {
//aCoder 为空直接返回
if (!aCoder) return;
//当前类是空对象 调用系统归档方法
if (self == (id)kCFNull) {
[((id<NSCoding>)self)encodeWithCoder:aCoder];
return;
}
//获取当前类的属性信息
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
//当前类时Foundation 类型 调用系统归档方法
if (modelMeta->_nsType) {
[((id<NSCoding>)self)encodeWithCoder:aCoder];
return;
}
//遍历所有属性
for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
//属性没有getter sel 直接返回
if (!propertyMeta->_getter) return;
//属性类型是 c 语言类型的数字
if (propertyMeta->_isCNumber) {
//转换为NSNumber
NSNumber *value = ModelCreateNumberFromProperty(self, propertyMeta);
//归档属性
if (value) [aCoder encodeObject:value forKey:propertyMeta->_name];
} else {
switch (propertyMeta->_type & YYEncodingTypeMask) {
//属性类型是对象类型
case YYEncodingTypeObject: {
//获取属性值
id value = ((id (*)(id, SEL))(void *)objc_msgSend)((id)self, propertyMeta->_getter);
if (value && (propertyMeta->_nsType || [value respondsToSelector:@selector(encodeWithCoder:)])) {
if ([value isKindOfClass:[NSValue class]]) {
if ([value isKindOfClass:[NSNumber class]]) {
//调用系统归档方法,归档属性
[aCoder encodeObject:value forKey:propertyMeta->_name];
}
} else {
//调用系统归档方法,归档属性
[aCoder encodeObject:value forKey:propertyMeta->_name];
}
}
} break;
case YYEncodingTypeSEL: {
SEL value = ((SEL (*)(id, SEL))(void *)objc_msgSend)((id)self, propertyMeta->_getter);
if (value) {
NSString *str = NSStringFromSelector(value);
//属性类型是SEL,转化为NSString,调用系统归档方法
[aCoder encodeObject:str forKey:propertyMeta->_name];
}
} break;
//属性类型是 YYEncodingTypeStruct, YYEncodingTypeUnion
case YYEncodingTypeStruct:
case YYEncodingTypeUnion: {
// 是系统类型的struct ,或者union
if (propertyMeta->_isKVCCompatible && propertyMeta->_isStructAvailableForKeyedArchiver) {
@try {
//调用kVC 获取值
NSValue *value = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
//调用系统方法
[aCoder encodeObject:value forKey:propertyMeta->_name];
} @catch (NSException *exception) {}
}
} break;
default:
break;
}
}
}
}
//解档
- (id)modelInitWithCoder:(NSCoder *)aDecoder {
//合理性判断
if (!aDecoder) return self;
if (self == (id)kCFNull) return self;
//获取当前类信息
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
//当前类是Foundation 类型返回自身
if (modelMeta->_nsType) return self;
//遍历所有属性
for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
//属性setter不存在直接返回
if (!propertyMeta->_setter) continue;
//属性的类型是c语言数字类型
if (propertyMeta->_isCNumber) {
//调用系统解档方法,获取值
NSNumber *value = [aDecoder decodeObjectForKey:propertyMeta->_name];
if ([value isKindOfClass:[NSNumber class]]) {
//赋值
ModelSetNumberToProperty(self, value, propertyMeta);
[value class];
}
} else {
YYEncodingType type = propertyMeta->_type & YYEncodingTypeMask;
switch (type) {
//属性的类型是对象类型
case YYEncodingTypeObject: {
//调用系统解档方法,获取值
id value = [aDecoder decodeObjectForKey:propertyMeta->_name];
//调用setter 赋值
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, propertyMeta->_setter, value);
} break;
//属性的类型是SEL
case YYEncodingTypeSEL: {
//调用系统解档方法,获取值
NSString *str = [aDecoder decodeObjectForKey:propertyMeta->_name];
//校验值的类型
if ([str isKindOfClass:[NSString class]]) {
//转化为SEL
SEL sel = NSSelectorFromString(str);
//调用setter 赋值
((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)self, propertyMeta->_setter, sel);
}
} break;
//属性的类型是Struct or Union
case YYEncodingTypeStruct:
case YYEncodingTypeUnion: {
//属性支持KVC
if (propertyMeta->_isKVCCompatible) {
@try {
//调用系统解档方法,获取值
NSValue *value = [aDecoder decodeObjectForKey:propertyMeta->_name];
//使用KVC 赋值
if (value) [self setValue:value forKey:propertyMeta->_name];
} @catch (NSException *exception) {}
}
} break;
default:
break;
}
}
}
return self;
}
hash
- (NSUInteger)modelHash {
if (self == (id)kCFNull) return [self hash];
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
if (modelMeta->_nsType) return [self hash];
NSUInteger value = 0;
NSUInteger count = 0;
//所有的属性的hash值异或
for (_YYModelPropertyMeta *propertyMeta in modelMeta->_allPropertyMetas) {
if (!propertyMeta->_isKVCCompatible) continue;
value ^= [[self valueForKey:NSStringFromSelector(propertyMeta->_getter)] hash];
count++;
}
//没有属性则返回自身地址
if (count == 0) value = (long)((__bridge void *)self);
return value;
}