YYModel源码浅析

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 过程:

  1. 在调用modelWithJSON: 方法后,会使用当前消息接收者Class,在缓存中获取_YYModelMeta(_YYModelMeta是对模型类信息的抽象).如果获取失败,会使用Class创建 _YYModelMeta,然后放入内存缓存.
  2. 获取_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;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,248评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,681评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,443评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,475评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,458评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,185评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,451评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,112评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,609评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,083评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,163评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,803评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,357评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,357评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,590评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,636评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,925评论 2 344

推荐阅读更多精彩内容