YYModel
提供高性能的數據與model
互相轉換的方法,并且提供了數據類型的適配和支持自定義屬性名和鍵的映射,使用起來非常方便.
YYModel提供的接口
YYModel
的接口以分類的形式提供:
NSObject 分類
@interface NSObject (YYModel)
//使用json數據創(chuàng)建對象,json的類型可以使NSDictionary,NSData,NSString
+ (nullable instancetype)modelWithJSON:(id)json;
//使用NSDictionary 創(chuàng)建對象
+ (nullable instancetype)modelWithDictionary:(NSDictionary *)dictionary;
//使用json數據為屬性賦值,json的類型可以使NSDictionary,NSData,NSString
- (BOOL)modelSetWithJSON:(id)json;
//使用NSDictionary為屬性賦值
//當dic中的數據類型與屬性的數據類型不匹配時,此方法會做一些適配,具體參考YYModel文檔
- (BOOL)modelSetWithDictionary:(NSDictionary *)dic;
//使用自身創(chuàng)建一個json對象
//當方法的接收者是NSArray,NSDictionary,NSSet時,只是把內部的對象轉換成json數據
- (nullable id)modelToJSONObject;
//使用自身創(chuàng)建一個json Data對象
//當方法的接收者是NSArray,NSDictionary,NSSet時,只是把內部的對象轉換成json string
- (nullable NSData *)modelToJSONData;
//使用自身創(chuàng)建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 協(xié)議
YYModel 協(xié)議
定義了屬性自定義映射的接口,以及轉換過程的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];
//使用類對象創(chuàng)建 _YYModelMeta,__YYModelMeta是對當前類信息的封裝
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:cls];
if (modelMeta->_hasCustomClassFromDictionary) {
//當前類實現了 modelCustomClassForDictionary:方法
cls = [cls modelCustomClassForDictionary:dictionary] ?: cls;
}
//創(chuàng)建實例
NSObject *one = [cls new];
//使用NSDictionary為屬性賦值,賦值成功則返回對象
if ([one modelSetWithDictionary:dictionary]) return one;
return nil;
}
從modelWithDictionary:
源碼可以看到,去邏輯流程是首先獲取當前類的信息,創(chuàng)建當前類實例,為當前類實例屬性賦值,返回當前實例.
接下來看看_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
創(chuàng)建_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) {
//重新創(chuàng)建類信息描述
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 {
//創(chuàng)建類對象的信息
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;
//創(chuàng)建 _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
//創(chuàng)建包含所有的map
NSMutableDictionary *mapper = [NSMutableDictionary new];
//創(chuàng)建使用keypath映射的屬性數組
NSMutableArray *keyPathPropertyMetas = [NSMutableArray new];
//創(chuàng)建使用多個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協(xié)議方法實現信息
_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
創(chuàng)建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) {
//調用實例方法創(chuàng)建
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++) {
//創(chuàng)建方法信息抽象對象 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++) {
//創(chuàng)建屬性信息抽象對象
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++) {
//創(chuàng)建實例成員信息抽象對象
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
創(chuàng)建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;
// 屬性所繼承的協(xié)議,可以為空
@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
創(chuàng)建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);
}
// 編碼類型字符串中, 每個< > 之間就是協(xié)議的名稱
NSMutableArray *protocols = nil;
while ([scanner scanString:@"<" intoString:NULL]) {
NSString* protocol = nil;
if ([scanner scanUpToString:@">" intoString: &protocol]) {
if (protocol.length) {
if (!protocols) protocols = [NSMutableArray new];
//將每個協(xié)議名稱添加到屬性數組中
[protocols addObject:protocol];
}
}
[scanner scanString:@">" intoString:NULL];
}
//保存協(xié)議名稱數組
_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
創(chuàng)建 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
創(chuàng)建_YYModelPropertyMeta
+ (instancetype)metaWithClassInfo:(YYClassInfo *)classInfo
propertyInfo:(YYClassPropertyInfo *)propertyInfo
generic:(Class)generic {
// support pseudo generic class with protocol name
//支持集合中的泛型為協(xié)議
if (!generic && propertyInfo.protocols) {
for (NSString *protocol in propertyInfo.protocols) {
Class cls = objc_getClass(protocol.UTF8String);
if (cls) {
generic = cls;
break;
}
}
}
//創(chuàng)建 _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;
});
//只有系統(tǒng)的結構體類型支持歸檔和解檔
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;
//創(chuàng)建 _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;
}
//創(chuàng)建 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) {
//解析屬性類型,按類型執(zhí)行真正的賦值操作
//屬性是 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, 創(chuàng)建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
}
//創(chuàng)建模型對象
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創(chuàng)建_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沒有設置過
//創(chuàng)建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是以分類方法的形式提供結構,所以沒有直接重寫系統(tǒng)的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];
//創(chuàng)建當前對象的新實例
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;
//當前類是空對象 調用系統(tǒng)歸檔方法
if (self == (id)kCFNull) {
[((id<NSCoding>)self)encodeWithCoder:aCoder];
return;
}
//獲取當前類的屬性信息
_YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:self.class];
//當前類時Foundation 類型 調用系統(tǒng)歸檔方法
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]]) {
//調用系統(tǒng)歸檔方法,歸檔屬性
[aCoder encodeObject:value forKey:propertyMeta->_name];
}
} else {
//調用系統(tǒng)歸檔方法,歸檔屬性
[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,調用系統(tǒng)歸檔方法
[aCoder encodeObject:str forKey:propertyMeta->_name];
}
} break;
//屬性類型是 YYEncodingTypeStruct, YYEncodingTypeUnion
case YYEncodingTypeStruct:
case YYEncodingTypeUnion: {
// 是系統(tǒng)類型的struct ,或者union
if (propertyMeta->_isKVCCompatible && propertyMeta->_isStructAvailableForKeyedArchiver) {
@try {
//調用kVC 獲取值
NSValue *value = [self valueForKey:NSStringFromSelector(propertyMeta->_getter)];
//調用系統(tǒng)方法
[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) {
//調用系統(tǒng)解檔方法,獲取值
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: {
//調用系統(tǒng)解檔方法,獲取值
id value = [aDecoder decodeObjectForKey:propertyMeta->_name];
//調用setter 賦值
((void (*)(id, SEL, id))(void *) objc_msgSend)((id)self, propertyMeta->_setter, value);
} break;
//屬性的類型是SEL
case YYEncodingTypeSEL: {
//調用系統(tǒng)解檔方法,獲取值
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 {
//調用系統(tǒng)解檔方法,獲取值
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;
}