YYModel源码详细解析-2

前言

阅读之前请见阅读YYModel源码详细解析-1,废话不多说,继续解析源码。

_YYModelMeta类

_YYModelMeta 来描述一个 YYClassInfo,完成所有的映射关系描述.

/// A class info in object model.
@interface _YYModelMeta : NSObject {
    @package
    YYClassInfo *_classInfo;
    /// Key:mapped key and key path, Value:_YYModelPropertyInfo.
    NSDictionary *_mapper;
    /// Array<_YYModelPropertyMeta>, all property meta of this model.
    NSArray *_allPropertyMetas;
    /// Array<_YYModelPropertyMeta>, property meta which is mapped to a key path.
    NSArray *_keyPathPropertyMetas;
    /// Array<_YYModelPropertyMeta>, property meta which is mapped to multi keys.
    NSArray *_multiKeysPropertyMetas;
    /// The number of mapped key (and key path), same to _mapper.count.
    NSUInteger _keyMappedCount;
    /// Model class type.
    YYEncodingNSType _nsType;
    
    /**
     @protocol YYModel 
     @optional 协议是否实现
     */
    BOOL _hasCustomWillTransformFromDictionary;
    BOOL _hasCustomTransformFromDictionary;
    BOOL _hasCustomTransformToDictionary;
    BOOL _hasCustomClassFromDictionary;
}
  • _mapper:存储 Json key 与 _PropertyMeta对象 的映射关系字典
  • _allPropertyMetas:数组存放所有的 PropertyMeta
  • _keyPathPropertyMetas:数组存放所有映射json keyPath 的 _PropertyMeta对象
  • _multiKeysPropertyMetas:数组存放所有映射多个json key 的 _PropertyMeta对象(一对多)
  • _keyMappedCount :属性总个数
  • _nsType:解析Class是Foundation类型哪一种
  • _hasCustomWillTransformFromDictionary、_hasCustomTransformFromDictionary、_hasCustomTransformToDictionary、_hasCustomClassFromDictionary,作用:判断YYModel协议方法是否实现

initWithClass方法
- (instancetype)initWithClass:(Class)cls {
// 初始化Class信息
YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls];
if (!classInfo) return nil;
self = [super init];

    // Get black list   黑名单
    NSSet *blacklist = nil;
    if ([cls respondsToSelector:@selector(modelPropertyBlacklist)]) { // 由用户传入的黑名单属性,不对其进行Json解析
        NSArray *properties = [(id)cls modelPropertyBlacklist];
        if (properties) {
            blacklist = [NSSet setWithArray:properties];
        }
    }
    
    // Get white list  白名单
    NSSet *whitelist = nil;
    if ([cls respondsToSelector:@selector(modelPropertyWhitelist)]) { // 由用户传入的白名单属性,解析
        NSArray *properties = [(id)cls modelPropertyWhitelist];
        if (properties) {
            whitelist = [NSSet setWithArray:properties];
        }
    }
    
    // 存储自定义映射Class字典
    NSDictionary *genericMapper = nil;
    if ([cls respondsToSelector:@selector(modelContainerPropertyGenericClass)]) {
        genericMapper = [(id)cls modelContainerPropertyGenericClass];
        if (genericMapper) { // 如果存在自定义映射Class,也就是说modelContainerPropertyGenericClass方法被实现了
            NSMutableDictionary *tmp = [NSMutableDictionary new];
            /**
             + (NSDictionary *)modelContainerPropertyGenericClass {
             return @{@"photos" : YYPhoto.class,
             @"likedUsers" : YYUser.class,
             @"likedUserIds" : NSNumber.class};
             }
             */
            [genericMapper enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { // 遍历字典
                // 如果传入的Key是字典或者数组直接返回
                if (![key isKindOfClass:[NSString class]]) return;
                /// 根据key获得对应的Class类型
                Class meta = object_getClass(obj);
                // 合法性检查,meta为空
                if (!meta) return;
                //
                if (class_isMetaClass(meta)) { // 如果传入的格式这样:YYUser.class 或 [YYUser class];或 Foundation Type
                    tmp[key] = obj;
                } else if ([obj isKindOfClass:[NSString class]]) { // 如果传入的格式这样:@“YYUser”
                    Class cls = NSClassFromString(obj); // 获得一个类的名称;如果当前项目没有加载这个类,返回nil
                    if (cls) { // 有该类存在
                        tmp[key] = cls; // 以json Key为key,value为所指定的类存入字典
                    }
                }
            }];
            // 遍历字典校验完毕后,传给自定义映射字典genericMapper
            genericMapper = tmp;
        }
    }
    
    // Create all property metas. 存储所有的property metas
    NSMutableDictionary *allPropertyMetas = [NSMutableDictionary new];
    YYClassInfo *curClassInfo = classInfo; // 传入的Class
    while (curClassInfo && curClassInfo.superCls != nil) { // recursive(递归) parse super class, but ignore root class (NSObject/NSProxy)(不对 Root Class((NSObject/NSProxy)) 做解析)
        
        // 1. classInfo - > propertyInfo; 2. classInfo -> propertyInfo -> PropertyMeta
        for (YYClassPropertyInfo *propertyInfo in curClassInfo.propertyInfos.allValues) { // 遍历class所有的属性
            if (!propertyInfo.name) continue; // 合法性检查
            if (blacklist && [blacklist containsObject:propertyInfo.name]) continue; 
            if (whitelist && ![whitelist containsObject:propertyInfo.name]) continue;
            // 初始化_YYModelPropertyMeta,classInfo -> propertyInfo -> PropertyMeta
            _YYModelPropertyMeta *meta = [_YYModelPropertyMeta metaWithClassInfo:classInfo
                                                                    propertyInfo:propertyInfo
                                                                         generic:genericMapper[propertyInfo.name]]; // 根据传入的参数,对PropertyMeta相关属性进行设置,返回元组信息
            if (!meta || !meta->_name) continue;
            if (!meta->_getter || !meta->_setter) continue; // 没有实现setter,getter
            if (allPropertyMetas[meta->_name]) continue; // 已经解析过的直接跳过
            allPropertyMetas[meta->_name] = meta; // 把属性的名称作为key存入allPropertyMetas,该字典存放所有的property metas
        }
        // 紧接着遍历父类信息
        curClassInfo = curClassInfo.superClassInfo;
    }
    if (allPropertyMetas.count) _allPropertyMetas = allPropertyMetas.allValues.copy;
    
    // create mapper
    NSMutableDictionary *mapper = [NSMutableDictionary new];
    NSMutableArray *keyPathPropertyMetas = [NSMutableArray new];
    NSMutableArray *multiKeysPropertyMetas = [NSMutableArray new];
    
    if ([cls respondsToSelector:@selector(modelCustomPropertyMapper)]) { // 是否创建映射
        // 返回自定义属性映射字典
        NSDictionary *customMapper = [(id )cls modelCustomPropertyMapper];
        // 遍历自定义属性字典,进行校验
        [customMapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyName, NSString *mappedToKey, BOOL *stop) {  // propertyName类中的属性名 mappedToKey  json当中的属性名
            // 根据属性名从allPropertyMetas取出对应的PropertyMetas
            _YYModelPropertyMeta *propertyMeta = allPropertyMetas[propertyName];
            if (!propertyMeta) return; // // 如果allPropertyMetas不存在该属性,也就是说想要属性映射并不存在该属性,那么是无法映射的,直接返回。allPropertyMetas相当于每个类的集合,存放所有的属性
            // 如果存在该属性,移除该属性,替换映射的属性名
            [allPropertyMetas removeObjectForKey:propertyName];
            // 确保映射的属性不是字典数组乱七八糟的类型
            if ([mappedToKey isKindOfClass:[NSString class]]) { // 映射属性名 @"page"  : @"p"
                // 映射属性名合法性校验
                /**
                 @"time":@"t";
                 */
                if (mappedToKey.length == 0) return;
                // 属性名映射一个简单的Json Key
                propertyMeta->_mappedToKey = mappedToKey; // 设置新属性名(映射的名称)
                
                // 如果有多级映射   componentsSeparatedByString:将字符串切割成数组
                /**
                 "ext" : {
                 "desc" : "A book written by J.K.Rowling."
                 },
                 格式1:
                 @"desc"  : @"ext.desc",
                存在点语法映射情况
                 
                 keyPath---(
                 ext,
                 desc
                 )
                 
                 格式2:
                 @{@"messageId":@"i",
                 @"content":@"c",
                 @"time":@"t"};
                 
                 */
                NSArray *keyPath = [mappedToKey componentsSeparatedByString:@"."]; // @"desc"  : @"ext.desc",
                if (keyPath.count > 1) { // 属性名映射一个Json keypath,如果是多级映射,keyPath = @[@"ect",@"desc"];,保存属性映射的json keyPaths
                    propertyMeta->_mappedToKeyPath = keyPath;
                    // 属性添加到使用keypaths映射的数组
                    [keyPathPropertyMetas addObject:propertyMeta];
                }
                /** 字符串格式3 多个属性映射同一个mappedToKey
                 {@"name":@"name", @"title":@"name", @"tip":@"name"}
                 */
                // 将多级映射中Key设置下一个属性
                // 使用Next指针串联mapper保存的mappedToKey当前映射的PropertyMeta对象
                propertyMeta->_next = mapper[mappedToKey] ?: nil; // 第一次不执行
                // 然后 再保存mappedToKey为key 映射 当前新的PropertyMeta对象
                mapper[mappedToKey] = propertyMeta; // 1.以映射属性名为Key将(propertyMeta)属性列表存入字典,如果是格式1多级映射propertyMeta->_mappedToKeyPath存在
                
            } else if ([mappedToKey isKindOfClass:[NSArray class]]) { // 如果映射的格式为  @"bookID": @[@"id", @"ID", @"book_id"]}; 同一个属性名映射到多个json key
                
                NSMutableArray *mappedToKeyArray = [NSMutableArray new];
                // 遍历 mappedToKey 数组
                for (NSString *oneKey in ((NSArray *)mappedToKey)) {
                    // 每一个 数组元素oneKey 必须是字符串
                    if (![oneKey isKindOfClass:[NSString class]]) continue;
                    // 字符串合法性校验
                    if (oneKey.length == 0) continue;
                    // 多个属性如果还有多级映射关系,例如 @"bookID": @[@"id", @"ext.ID", @"book_id"]}
                    NSArray *keyPath = [oneKey componentsSeparatedByString:@"."];
                    if (keyPath.count > 1) { // NSArray
                        // keypath 当做一个数组保存到数组,例如保存@[@"ext",@"ID"]
                        [mappedToKeyArray addObject:keyPath];
                    } else { // NSString
                        // keypath 当做一个字符串保存到数组,例如保存id、book_id
                        [mappedToKeyArray addObject:oneKey];
                    }
                    // 因为是 `一个属性` 映射 `多个json key
                    // 只能保存第一个_mappedToKey(json key),否则后面的_mappedToKey被覆盖了
                    if (!propertyMeta->_mappedToKey) {   //  _mappedToKeyPath可能为nil;_mappedToKey,_mappedToKeyPath这两个属性可以为后面的方法区别用多级映射(multi)或者一级映射方法
                        propertyMeta->_mappedToKey = oneKey; // 保存数组中第一个oneKey,例如id
                        propertyMeta->_mappedToKeyPath = keyPath.count > 1 ? keyPath : nil; // 保存数组中第一个_mappedToKeyPath,例如ext.ID
                    }
                }
                // 属性 没有映射任何的json key
                if (!propertyMeta->_mappedToKey) return;
                // 保存 当前属性描述的所有json key 映射数组
                propertyMeta->_mappedToKeyArray = mappedToKeyArray;
                // 记录一个 <1属性:n 个 jsonkey>映射关系 的属性
                [multiKeysPropertyMetas addObject:propertyMeta];
                // 多(属性)对一(json key)
                propertyMeta->_next = mapper[mappedToKey] ?: nil;
                mapper[mappedToKey] = propertyMeta;
            }
        }];
    }
    // 注意,如上只对映射字典中给出的属性进行处理
    // 如上处理过的属性都从属性字典中删除
    // allPropertyMetas此时剩下的属性,都是没有配置映射规则的
    // 处理没有映射配置的属性
    // 默认 属性映射json key >>>> 属性的名字
    [allPropertyMetas enumerateKeysAndObjectsUsingBlock:^(NSString *name, _YYModelPropertyMeta *propertyMeta, BOOL *stop) {
        // 简单属性映射
        propertyMeta->_mappedToKey = name;
        // 让映射到相同json key的 不同属性(多属性对一个json key) 使用next指针串联
        propertyMeta->_next = mapper[name] ?: nil;
        // 保存新的映射json key
        mapper[name] = propertyMeta;
    }];
    // 修正映射配置数据
    if (mapper.count) _mapper = mapper;
    if (keyPathPropertyMetas) _keyPathPropertyMetas = keyPathPropertyMetas;
    if (multiKeysPropertyMetas) _multiKeysPropertyMetas = multiKeysPropertyMetas;
    
    _classInfo = classInfo;
    _keyMappedCount = _allPropertyMetas.count;
    _nsType = YYClassGetNSType(cls);
    /**
     @protocol YYModel 
     @optional
     */
    /** 
     instancesRespondToSelector:被调用时,动态方法是有机会的首先为selector提供一个IMP,如果该类对应的Property有modelCustomWillTransformFromDictionary/modelCustomTransformFromDictionary/modelCustomTransformToDictionary/_hasCustomClassFromDictionary方法实现方法,则返回YES
     **/
    _hasCustomWillTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomWillTransformFromDictionary:)]);
    _hasCustomTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformFromDictionary:)]);
    _hasCustomTransformToDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformToDictionary:)]);
    _hasCustomClassFromDictionary = ([cls respondsToSelector:@selector(modelCustomClassForDictionary:)]);
    
    return self;
}

metaWithClass方法

/// Returns the cached model class meta 缓存优化 Class 与 _YYModelMeta对象
+ (instancetype)metaWithClass:(Class)cls {
    // 空处理
    if (!cls) return nil;
    // 单例字典来缓存优化处理_YYModelMeta对象,类似YYClassInfo对象
    static CFMutableDictionaryRef cache;  // 字典:保存数据
    static dispatch_once_t onceToken;
    // dispatch_semaphore_t 计数器
    static dispatch_semaphore_t lock;
    dispatch_once(&onceToken, ^{
        // // 初始化字典
        cache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        /** dispatch_semaphore_create
         创建新的计数信号量的初始值。
         新创建的信号量,或nil失败。
         创建一个信号量,只允许一个线程通过
         */
        lock = dispatch_semaphore_create(1);
    });
    /**  dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 如果semaphore计数大于等于1.计数-1,返回,程序继续运行。如果计数为0,则等待。DISPATCH_TIME_FOREVER这里设置的等待时间是一直等待。dispatch_semaphore_signal(semaphore);计数+1.在这两句代码中间的执行代码,每次只会允许一个线程进入,这样就有效的保证了在多线程环境下,只能有一个线程进入。
     **/
    dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
    // // 查询缓存获取_YYModelMeta对象
    _YYModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls));
    // dispatch_semaphore_signal(semaphore);计数+1.在这两句代码中间的执行代码,每次只会允许一个线程进入,这样就有效的保证了在多线程环境下,只能有一个线程进入。
    dispatch_semaphore_signal(lock);
    if (!meta || meta->_classInfo.needUpdate) {
        // 初始化_YYModelMeta传入cls对象设置相应的属性 = 更新
        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;
}


/**
 Get number from property.()
 @discussion Caller should hold strong reference to the parameters before this function returns.
 @param model Should not be nil.
 @param meta  Should not be nil, meta.isCNumber should be YES, meta.getter should not be nil.
 @return A number object, or nil if failed.
 从_YYModelPropertyMeta将c基本数值类型的属性 统一按照 NSNumber 处理。
 discussion:调用方在函数返回之前对参数具有很强的引用。
 @param 模型不应该是nil。
 @param meta不应为零,meta.iscnumber应该为YES,meta.getter不应该是nil。
 “返回一个number对象,如果failed返回nil,
 
 格式:
 ((void (*)(id, SEL, 方法形参类型))(void *) objc_msgSend)(对象, SEL, 方法执行的参数);
 */
static force_inline NSNumber *ModelCreateNumberFromProperty(__unsafe_unretained id model,
                                                            __unsafe_unretained _YYModelPropertyMeta *meta) {
    // 按照不同数据类型取值,并转换成NSNumber
    switch (meta->_type & YYEncodingTypeMask) {
        case YYEncodingTypeBool: {
            return @(((bool (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
        }
        case YYEncodingTypeInt8: {
            return @(((int8_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
        }
        case YYEncodingTypeUInt8: {
            return @(((uint8_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
        }
        case YYEncodingTypeInt16: {
            return @(((int16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
        }
        case YYEncodingTypeUInt16: {
            return @(((uint16_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
        }
        case YYEncodingTypeInt32: {
            return @(((int32_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
        }
        case YYEncodingTypeUInt32: {
            return @(((uint32_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
        }
        case YYEncodingTypeInt64: {
            return @(((int64_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
        }
        case YYEncodingTypeUInt64: {
            return @(((uint64_t (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter));
        }
        case YYEncodingTypeFloat: {
            float num = ((float (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
            if (isnan(num) || isinf(num)) return nil;
            return @(num);
        }
        case YYEncodingTypeDouble: {
            double num = ((double (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
            if (isnan(num) || isinf(num)) return nil;
            return @(num);
        }
        case YYEncodingTypeLongDouble: {
            double num = ((long double (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
            if (isnan(num) || isinf(num)) return nil;
            return @(num);
        }
        default: return nil;
    }
}

/**
 Set number to property.
 @discussion Caller should hold strong reference to the parameters before this function returns.
 @param model Should not be nil.
 @param num   Can be nil.
 @param meta  Should not be nil, meta.isCNumber should be YES, meta.setter should not be nil.
 获取 c基本数值类型的属性值
 discussion: 调用方在函数返回之前对参数具有很强的引用。
 @param:model 被_YYModelMeta解析过的实体类对象
 @param: num  要设置的NSNumber值
 @param:meta:(要设置值的属性的描述对象)   meta不应为nil,meta.iscnumber应该为YES,meta.setter不应该为nil
 格式:
 ((void (*)(id, SEL, 方法形参类型))(void *) objc_msgSend)(对象, SEL, 方法执行的参数);
 */
static force_inline void ModelSetNumberToProperty(__unsafe_unretained id model,
                                                  __unsafe_unretained NSNumber *num,
                                                  __unsafe_unretained _YYModelPropertyMeta *meta) {
    switch (meta->_type & YYEncodingTypeMask) {
        case YYEncodingTypeBool: {
            /** objc_msgSend
             用一个简单的返回值发送消息到一个类的实例。
             方法的返回值。
             
             self
             指向类的实例的一个指针,该实例将接收该消息。
             OP
             处理消息的方法的选择器。
             …
             一个包含参数的变量参数列表。
             返回方法的返回值。
             */
            ((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)model, meta->_setter, num.boolValue);
        } break;
        case YYEncodingTypeInt8: {
            ((void (*)(id, SEL, int8_t))(void *) objc_msgSend)((id)model, meta->_setter, (int8_t)num.charValue);
        } break;
        case YYEncodingTypeUInt8: {
            ((void (*)(id, SEL, uint8_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint8_t)num.unsignedCharValue);
        } break;
        case YYEncodingTypeInt16: {
            ((void (*)(id, SEL, int16_t))(void *) objc_msgSend)((id)model, meta->_setter, (int16_t)num.shortValue);
        } break;
        case YYEncodingTypeUInt16: {
            ((void (*)(id, SEL, uint16_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint16_t)num.unsignedShortValue);
        } break;
        case YYEncodingTypeInt32: {
            ((void (*)(id, SEL, int32_t))(void *) objc_msgSend)((id)model, meta->_setter, (int32_t)num.intValue);
        }
        case YYEncodingTypeUInt32: {
            ((void (*)(id, SEL, uint32_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint32_t)num.unsignedIntValue);
        } break;
        case YYEncodingTypeInt64: {
            if ([num isKindOfClass:[NSDecimalNumber class]]) {
                ((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue);
            } else {
                ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.longLongValue);
            }
        } break;
        case YYEncodingTypeUInt64: {
            if ([num isKindOfClass:[NSDecimalNumber class]]) {
                ((void (*)(id, SEL, int64_t))(void *) objc_msgSend)((id)model, meta->_setter, (int64_t)num.stringValue.longLongValue);
            } else {
                ((void (*)(id, SEL, uint64_t))(void *) objc_msgSend)((id)model, meta->_setter, (uint64_t)num.unsignedLongLongValue);
            }
        } break;
        case YYEncodingTypeFloat: {
            float f = num.floatValue;
            if (isnan(f) || isinf(f)) f = 0;
            ((void (*)(id, SEL, float))(void *) objc_msgSend)((id)model, meta->_setter, f);
        } break;
        case YYEncodingTypeDouble: {
            double d = num.doubleValue;
            if (isnan(d) || isinf(d)) d = 0;
            ((void (*)(id, SEL, double))(void *) objc_msgSend)((id)model, meta->_setter, d);
        } break;
        case YYEncodingTypeLongDouble: {
            long double d = num.doubleValue;
            if (isnan(d) || isinf(d)) d = 0;
            ((void (*)(id, SEL, long double))(void *) objc_msgSend)((id)model, meta->_setter, (long double)d);
        } // break; commented for code coverage in next line
        default: break;
    }
}

/**
 Set value to model with a property meta.
 
 @discussion Caller should hold strong reference to the parameters before this function returns.
 
 @param model Should not be nil.
 @param value Should not be nil, but can be NSNull.
 @param meta  Should not be nil, and meta->_setter should not be nil.
 
 根据对象属性的描述, 将id类型的对象设置给属性
 
 */
static void ModelSetValueForProperty(__unsafe_unretained id model,
                                     __unsafe_unretained id value,
                                     __unsafe_unretained _YYModelPropertyMeta *meta) {
  
    /** 根据对象属性的描述,来设置id类型的属性值,防止类型转换错误导致崩溃
    
     - 属性`变量类型`
     - 设置给属性的`值类型`
     */
    if (meta->_isCNumber) { // 如果是C语言基本数字类型(注意: NSNumber不是基本类型)
        // id value >>> NSNumber
        NSNumber *num = YYNSNumberCreateFromID(value);
        // 将NSNumber值 设置给实体对象的属性
        ModelSetNumberToProperty(model, num, meta);
        if (num) [num class]; // hold the number 释放num
    } else if (meta->_nsType) { // 如果属性变量是Foundation框架
        if (value == (id)kCFNull) { // 值为空,直接向model的setter发送nil消息
            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
        } else {
            
            switch (meta->_nsType) { // 区分不同的Foundation Class类型设值
                case YYEncodingTypeNSString: // 如果属性变量是NSString
                case YYEncodingTypeNSMutableString: { // 如果是类型是NSMutableString
                    // 依次判断value类型
                    if ([value isKindOfClass:[NSString class]]) {// 值的类型NSString
                        
                        if (meta->_nsType == YYEncodingTypeNSString) { // 属性类型是NSString
                            // 向model的setter发送value消息
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value); // copy
                        } else { // 属性类型是NSMutaleString

                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, ((NSString *)value).mutableCopy); // mutableCopy
                        }
                    } else if ([value isKindOfClass:[NSNumber class]]) { // value类型为NSNumber
                        
                        // 判断类型是NSString/NSMutaleString,向model的setter发送value消息
                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
                                                                       meta->_setter,
                                                                       (meta->_nsType == YYEncodingTypeNSString) ?
                                                                       ((NSNumber *)value).stringValue :
                                                                       ((NSNumber *)value).stringValue.mutableCopy);
                    } else if ([value isKindOfClass:[NSData class]]) { // value类型为NSData
                        NSMutableString *string = [[NSMutableString alloc] initWithData:value encoding:NSUTF8StringEncoding];
                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, string);
                    } else if ([value isKindOfClass:[NSURL class]]) { // value类型为NSURL
                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
                                                                       meta->_setter,
                                                                       (meta->_nsType == YYEncodingTypeNSString) ?
                                                                       ((NSURL *)value).absoluteString :
                                                                       ((NSURL *)value).absoluteString.mutableCopy);
                    } else if ([value isKindOfClass:[NSAttributedString class]]) {// value类型为NSAttributedString

                        ((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: {
                    if (meta->_nsType == YYEncodingTypeNSNumber) { // 属性变量类型是Foundation框架NSNumber
                        // value id -> NSNumber
                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSNumberCreateFromID(value));
                    } else if (meta->_nsType == YYEncodingTypeNSDecimalNumber) { // 属性变量类型是Foundation框架NSDecimalNumber
                        if ([value isKindOfClass:[NSDecimalNumber class]]) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
                        } 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);
                        } 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
                        if ([value isKindOfClass:[NSValue class]]) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
                        }
                    }
                } break;
                    
                case YYEncodingTypeNSData:
                case YYEncodingTypeNSMutableData: {
                    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: {
                    if ([value isKindOfClass:[NSDate class]]) {
                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
                    } else if ([value isKindOfClass:[NSString class]]) {//value类型是NSString
                        // YYNSDateFromString: NSString转换NSDate
                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSDateFromString(value));
                    }
                } break;
                    
                case YYEncodingTypeNSURL: {
                    if ([value isKindOfClass:[NSURL class]]) {
                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
                    } else if ([value isKindOfClass:[NSString class]]) { // value属性类型是NSString,NSString - > NSURL
                        // 字符串去掉多余的空格
                        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、NSMutableArray
                case YYEncodingTypeNSArray:
                case YYEncodingTypeNSMutableArray: {
                    // 看是否配置有自定义映射数组每一个对象的Class映射
                    if (meta->_genericCls) {
                        //  有数组元素Class配置
                        NSArray *valueArr = nil;
                        // 值类型只能是: NSArray、NSSet
                        if ([value isKindOfClass:[NSArray class]]) valueArr = value; // 值是数组
                        else if ([value isKindOfClass:[NSSet class]]) valueArr = ((NSSet *)value).allObjects; // 值是集合
                        // 转换传入的值数组 成为 实体类对象的数组
                        if (valueArr) {
                            // 保存所有转成实体对象的数组
                            NSMutableArray *objectArr = [NSMutableArray new];
                            // 遍历数组每一个对象
                            for (id one in valueArr) {
                                // 支持数组元素类型: 实体类对象、字典对象
                                if ([one isKindOfClass:meta->_genericCls]) {
                                    // 数组元素Class == 配置有映射Class
                                    [objectArr addObject:one];
                                } else if ([one isKindOfClass:[NSDictionary class]]) {
                                    // 数组元素Class == NSDictionary Class,需要转换成实体
                                    
                                    // 获取 属性 配置的 实体类Class
                                    Class cls = meta->_genericCls;
                                    if (meta->_hasCustomClassFromDictionary) { // 有自定义Class映射字典
                                        // 先使用用户设置的修正字典的Class
                                        // 使用 -[NSObject modelCustomClassForDictionary:] 传入当前字典对象,得到的对应Class
                                        cls = [cls modelCustomClassForDictionary:one];
                                        // 如果没有设置,就使用当前属性配置的Class
                                        //使用 -[NSObject mapping_containerPropertiesMappings]返回的属性对应的Class
                                        if (!cls) cls = meta->_genericCls;
                                    }
                                    // 创建一个新的NSObject对象
                                    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 { // 没有数组元素Class配置
                        // value是NSArray
                        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]]) {  // value是NSSet
                            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;
                    
                case YYEncodingTypeNSDictionary:
                case YYEncodingTypeNSMutableDictionary: {
                    if ([value isKindOfClass:[NSDictionary class]]) {
                        if (meta->_genericCls) {
                            NSMutableDictionary *dic = [NSMutableDictionary new];
                            [((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];
                                    if (newOne) dic[oneKey] = newOne;
                                }
                            }];
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, dic);
                        } else {
                            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;
                // 属性变量 NSArray、NSMutableArray
                case YYEncodingTypeNSSet:
                case YYEncodingTypeNSMutableSet: {
                    NSSet *valueSet = nil;
                    // 属性变量是NSArray类型时
                    // 看是否配置有数组中每一个对象的Class映射
                    
                    // value类型只能是: NSArray、NSSet
                    if ([value isKindOfClass:[NSArray class]]) valueSet = [NSMutableSet setWithArray:value];
                    else if ([value isKindOfClass:[NSSet class]]) valueSet = ((NSSet *)value);
                    // 有数组元素Class配置
                    if (meta->_genericCls) {
                        NSMutableSet *set = [NSMutableSet new];
                        for (id one in valueSet) { // 遍历数组每一个对象
                            if ([one isKindOfClass:meta->_genericCls]) {
                                [set addObject:one];
                            } else if ([one isKindOfClass:[NSDictionary class]]) {
                                Class cls = meta->_genericCls;
                                if (meta->_hasCustomClassFromDictionary) { // 是否实现映射字典
                                    // 数组元素Class == NSDictionary Class,需要转换成实体
                                    // 获取 属性 配置的 实体类Class
                                    cls = [cls modelCustomClassForDictionary:one];
                                    // 支持数组元素类型: 实体类对象、字典对象
                                    if (!cls) cls = meta->_genericCls; // for xcode code coverage
                                }
                                // 创建一个新的NSObject对象
                                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 {
                        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) {
                    ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
                } else if ([value isKindOfClass:meta->_cls] || !meta->_cls) {
                    ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)value);
                } else if ([value isKindOfClass:[NSDictionary class]]) {
                    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 modelSetWithDictionary:value];
                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)one);
                    }
                }
            } break;
                
            case YYEncodingTypeClass: {
                if (isNull) {
                    ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)NULL);
                } else {
                    Class cls = nil;
                    if ([value isKindOfClass:[NSString class]]) {
                        cls = NSClassFromString(value);
                        if (cls) {
                            ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)cls);
                        }
                    } else {
                        cls = object_getClass(value);
                        if (cls) {
                            if (class_isMetaClass(cls)) {
                                ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)value);
                            }
                        }
                    }
                }
            } break;
                
            case  YYEncodingTypeSEL: {
                if (isNull) {
                    ((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)NULL);
                } 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;
                
            case YYEncodingTypeBlock: {
                // Block类型使用: void (^)(void)
                if (isNull) {
                    ((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())NULL);
                } else if ([value isKindOfClass:YYNSBlockClass()]) {
                    ((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())value);
                }
            } break;
                
                // 注意: c类型需要使用NSValue对象包装
            case YYEncodingTypeStruct:
            case YYEncodingTypeUnion:
            case YYEncodingTypeCArray: {
                if ([value isKindOfClass:[NSValue class]]) {
                    // 传入value的编码
                    const char *valueType = ((NSValue *)value).objCType;
                    // 属性变量类型的编码
                    const char *metaType = meta->_info.typeEncoding.UTF8String;
                    // 比较两个编码的内容是否一致
                    if (valueType && metaType && strcmp(valueType, metaType) == 0) {
                        // 结构体实例使用KVC设置给属性变量
                        [model setValue:value forKey:meta->_name];
                    }
                }
            } break;
            // 指针类型value,使用 void* 万能指针类型
            case YYEncodingTypePointer:
            case YYEncodingTypeCString: {
                if (isNull) {
                    ((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, (void *)NULL);
                } else if ([value isKindOfClass:[NSValue class]]) {
                    NSValue *nsValue = value;
                    // 判断传入值的类型,是否是 void* 指针类型
                    // TODO: 为什么CString要按照void*指针类型了?
                    // 因为 [NSValue valueWithPointer:(nullable const void *)]; 将传入的指针转换成 void* 类型了
                    // 所以再通过NSValue获取到指针的类型时,就是 void* ,而其编码就是 `^v`
                    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;
        }
    }
}


typedef struct {
    // 实体类Class的描述类
    void *modelMeta;  ///< _YYModelMeta
    // 设置给哪个实体类对象
    void *model;      ///< id (self)
    // 要设置的值
    void *dictionary; ///< NSDictionary (json)
} ModelSetContext;

/**
 Apply function for dictionary, to set the key-value pair to model.
 
 @param _key     should not be nil, NSString.
 @param _value   should not be nil.
 @param _context _context.modelMeta and _context.model should not be nil.
 
 应用字典函数,设置键值对模型。
 @param _key不应为nil,NSString。
 @param _value不应为nil。
 @param _context _context.modelmeta和_context.model不应该是NIL。
 
 
 
 */
/**
 *  直接给出jsonkey,然后找到映射的属性描述
 *
 *  @param _jsonKey json key
 *  @param _value   要设置的value
 *  @param _context ModelSetContext实例
 */
static void ModelSetWithDictionaryFunction(const void *_key, const void *_value, void *_context) {
    // c类型转换oc类型
    ModelSetContext *context = _context;
    __unsafe_unretained _YYModelMeta *meta = (__bridge _YYModelMeta *)(context->modelMeta);
    // 从_YYModelMeta->_mapper字典,获取_mapper对应的_YYModelPropertyMeta对象
    __unsafe_unretained _YYModelPropertyMeta *propertyMeta = [meta->_mapper objectForKey:(__bridge id)(_key)];
    // c类型转换oc类型,实体类对象
    __unsafe_unretained id model = (__bridge id)(context->model);
    // 当有多个不同属性映射一个_mapper
    while (propertyMeta) {
        // 设置当前属性
        if (propertyMeta->_setter) {
            // 重要方法:设置键值对模型
            // 根据属性描述,将value设置给实体类对象
            ModelSetValueForProperty(model, (__bridge __unsafe_unretained id)_value, propertyMeta);
        }
        // 当前_mapper有多个属性同时映射
        propertyMeta = propertyMeta->_next;
    };
}

/**
 Apply function for model property meta, to set dictionary to model.
 
 @param _propertyMeta should not be nil, _YYModelPropertyMeta.
 @param _context      _context.model and _context.dictionary should not be nil.
 
 应用模型属性元函数,对模型集进行字典。
 @param _propertymeta不应为nil,_yymodelpropertymeta。
 @param _context _context.model和_context.dictionary不应该是nil。
 */

/**
 *  先传入属性描述,再从属性描述获取属性映射的jsonkey,然后从传入的字典获取jsonvalue,然后设置给实体类对象
 *
 *  @param _propertyMeta 属性描述对象
 *  @param context       ModelSetContext实例
 */
static void ModelSetWithPropertyMetaArrayFunction(const void *_propertyMeta, void *_context) {
    // 类型转换
    ModelSetContext *context = _context;
    // 从context获取字典对象
    __unsafe_unretained NSDictionary *dictionary = (__bridge NSDictionary *)(context->dictionary);
    // 属性必须存在setter方法实现
    __unsafe_unretained _YYModelPropertyMeta *propertyMeta = (__bridge _YYModelPropertyMeta *)(_propertyMeta);
    if (!propertyMeta->_setter) return;
    id value = nil;
    
    if (propertyMeta->_mappedToKeyArray) {
        // 属性映射多个_mappedToKey(1.一个字符串key 2.keypath)
        value = YYValueForMultiKeys(dictionary, propertyMeta->_mappedToKeyArray);
    } else if (propertyMeta->_mappedToKeyPath) {
        // 属性映射一个_mappedToKeyPath
        value = YYValueForKeyPath(dictionary, propertyMeta->_mappedToKeyPath);
    } else {
        // 属性映射一个单独的json Ke
        value = [dictionary objectForKey:propertyMeta->_mappedToKey];
    }
    // 将从json字典取出的值设置给实体对象
    if (value) {
        // 取出Context中的实体类对象
        __unsafe_unretained id model = (__bridge id)(context->model);
        // 调用给对象设置id值的c方法
        ModelSetValueForProperty(model, value, propertyMeta);
    }
}

你可能感兴趣的:(YYModel源码详细解析-2)