YYModel源碼淺析

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

  1. 在調用modelWithJSON: 方法后,會使用當前消息接收者Class,在緩存中獲取_YYModelMeta(_YYModelMeta是對模型類信息的抽象).如果獲取失敗,會使用Class創(chuàng)建 _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沒有設置過
                    //創(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;
}
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末阀捅,一起剝皮案震驚了整個濱河市屎飘,隨后出現的幾起案子艰额,更是在濱河造成了極大的恐慌,老刑警劉巖晦雨,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡种冬,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門还栓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來碌廓,“玉大人,你說我怎么就攤上這事剩盒」绕牛” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵辽聊,是天一觀的道長纪挎。 經常有香客問我,道長跟匆,這世上最難降的妖魔是什么异袄? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮玛臂,結果婚禮上烤蜕,老公的妹妹穿的比我還像新娘封孙。我一直安慰自己,他們只是感情好讽营,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布虎忌。 她就那樣靜靜地躺著,像睡著了一般橱鹏。 火紅的嫁衣襯著肌膚如雪膜蠢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天莉兰,我揣著相機與錄音挑围,去河邊找鬼。 笑死糖荒,一個胖子當著我的面吹牛杉辙,可吹牛的內容都是我干的。 我是一名探鬼主播捶朵,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼奏瞬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泉孩?” 一聲冷哼從身側響起硼端,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎寓搬,沒想到半個月后珍昨,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡句喷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年镣典,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唾琼。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡兄春,死狀恐怖,靈堂內的尸體忽然破棺而出锡溯,到底是詐尸還是另有隱情赶舆,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布祭饭,位于F島的核電站芜茵,受9級特大地震影響,放射性物質發(fā)生泄漏倡蝙。R本人自食惡果不足惜九串,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧猪钮,春花似錦品山、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拂玻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宰译,已是汗流浹背檐蚜。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沿侈,地道東北人闯第。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像缀拭,于是被迫代替她去往敵國和親咳短。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內容