美文网首页源码阅读及解析源码阅读及剖析
YYMode ——_YYModelMeta 源码学习

YYMode ——_YYModelMeta 源码学习

作者: Laughingg | 来源:发表于2016-07-28 14:27 被阅读73次
    /// A class info in object model.
    /// 模型对象的 “元类” 信息
    @interface _YYModelMeta : NSObject {
        @package
    
        // 记录的类信息
        YYClassInfo *_classInfo;
        /// Key:mapped key and key path, Value:_YYModelPropertyMeta.
        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;
        
        BOOL _hasCustomWillTransformFromDictionary;
        BOOL _hasCustomTransformFromDictionary;
        BOOL _hasCustomTransformToDictionary;
        BOOL _hasCustomClassFromDictionary;
    }
    @end
    
    // 模型元
    @implementation _YYModelMeta
    - (instancetype)initWithClass:(Class)cls {
    
        // 获取类信息
        /*
          在这一步已经对类的进行了处理,获取了属性列表,变量列表,方法列表。处理的属性和变量的类型编码格式。
         并将 class 的这些信息都添加到了 缓存池中。
        */
        YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls];
    
        // 初始化失败就直接返回 nil
        if (!classInfo) return nil;
    
        // 初始化父类信息
        self = [super init];
        
        // Get black list   获取黑名单 (NSSet 可以去重)
        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  获取 容器属性 泛类
        /*
          容器: dict , array ,set
         Example:
            @class YYShadow, YYBorder, YYAttachment;
     
            @interface YYAttributes
            @property NSString *name;
            @property NSArray *shadows;
            @property NSSet *borders;
            @property NSDictionary *attachments;
            @end
     
            @implementation YYAttributes
            + (NSDictionary *)modelContainerPropertyGenericClass {
                return @{@"shadows" : [YYShadow class],
                         @"borders" : YYBorder.class,
                         @"attachments" : @"YYAttachment" };
            }
            @end
        */
        // 泛型映射
        NSDictionary *genericMapper = nil;
        if ([cls respondsToSelector:@selector(modelContainerPropertyGenericClass)]) {
            // 获取映射的 class 字典
            genericMapper = [(id<YYModel>)cls modelContainerPropertyGenericClass];
    
            if (genericMapper) {
                NSMutableDictionary *tmp = [NSMutableDictionary new];
    
                // 泛型映射便利
                [genericMapper enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
    
                    // key 为 非字符串  直接返回
                    if (![key isKindOfClass:[NSString class]]) return;
    
                    // 获取对象的类 
                    Class meta = object_getClass(obj);
    
                    // 获取失败直接返回
                    if (!meta) return;
    
                    // 判断是否是 元 类
                    /*
                       关乎为什么要判断是否是 元 类
                      http://stackoverflow.com/questions/6536244/check-if-object-is-class-type
                    */
                    if (class_isMetaClass(meta)) {   // 确定传入的是一个 类, 不是一个实例对象 
    
                        // 添加进字典
                        tmp[key] = obj;
    
                        // objc 是 string , 将 objc 转换为 class 加入到字典
                    } 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;
        while (curClassInfo && curClassInfo.superCls != nil) { 
              // recursive parse super class, but ignore root class (NSObject/NSProxy)
              // 递归解析父类,但是会忽略根类      
    
             // 便利当前类的属性信息
            for (YYClassPropertyInfo *propertyInfo in curClassInfo.propertyInfos.allValues) {
                //   属性名为 nil 就直接进入下一次循环
                if (!propertyInfo.name) continue;
    
    
    
                // 这下面要做的就是 剔除黑名单,剔除非白名单。
                //  黑名单有值,并属性名称包含在黑名单中就直接进入下一次循环
                if (blacklist && [blacklist containsObject:propertyInfo.name]) continue;
    
                 //  白名单有值 ,请属性不在白名单中就直接进入下一次循环
                if (whitelist && ![whitelist containsObject:propertyInfo.name]) continue;
    
    
                // 包含属性的处理
                // 模型属性 “元”
                _YYModelPropertyMeta *meta = [_YYModelPropertyMeta metaWithClassInfo:classInfo
                                                                        propertyInfo:propertyInfo
                                                                             generic:genericMapper[propertyInfo.name]];
                if (!meta || !meta->_name) continue;
                if (!meta->_getter || !meta->_setter) continue;
                if (allPropertyMetas[meta->_name]) continue;
                allPropertyMetas[meta->_name] = meta;
            }
            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 <YYModel>)cls modelCustomPropertyMapper];
            [customMapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyName, NSString *mappedToKey, BOOL *stop) {
                _YYModelPropertyMeta *propertyMeta = allPropertyMetas[propertyName];
                if (!propertyMeta) return;
                [allPropertyMetas removeObjectForKey:propertyName];
                
                if ([mappedToKey isKindOfClass:[NSString class]]) {
                    if (mappedToKey.length == 0) return;
                    
                    propertyMeta->_mappedToKey = mappedToKey;
                    NSArray *keyPath = [mappedToKey componentsSeparatedByString:@"."];
                    for (NSString *onePath in keyPath) {
                        if (onePath.length == 0) {
                            NSMutableArray *tmp = keyPath.mutableCopy;
                            [tmp removeObject:@""];
                            keyPath = tmp;
                            break;
                        }
                    }
                    if (keyPath.count > 1) {
                        propertyMeta->_mappedToKeyPath = keyPath;
                        [keyPathPropertyMetas addObject:propertyMeta];
                    }
                    propertyMeta->_next = mapper[mappedToKey] ?: nil;
                    mapper[mappedToKey] = propertyMeta;
                    
                } else if ([mappedToKey isKindOfClass:[NSArray class]]) {
                    
                    NSMutableArray *mappedToKeyArray = [NSMutableArray new];
                    for (NSString *oneKey in ((NSArray *)mappedToKey)) {
                        if (![oneKey isKindOfClass:[NSString class]]) continue;
                        if (oneKey.length == 0) continue;
                        
                        NSArray *keyPath = [oneKey componentsSeparatedByString:@"."];
                        if (keyPath.count > 1) {
                            [mappedToKeyArray addObject:keyPath];
                        } else {
                            [mappedToKeyArray addObject:oneKey];
                        }
                        
                        if (!propertyMeta->_mappedToKey) {
                            propertyMeta->_mappedToKey = oneKey;
                            propertyMeta->_mappedToKeyPath = keyPath.count > 1 ? keyPath : nil;
                        }
                    }
                    if (!propertyMeta->_mappedToKey) return;
                    
                    propertyMeta->_mappedToKeyArray = mappedToKeyArray;
                    [multiKeysPropertyMetas addObject:propertyMeta];
                    
                    propertyMeta->_next = mapper[mappedToKey] ?: nil;
                    mapper[mappedToKey] = propertyMeta;
                }
            }];
        }
        
        [allPropertyMetas enumerateKeysAndObjectsUsingBlock:^(NSString *name, _YYModelPropertyMeta *propertyMeta, BOOL *stop) {
            propertyMeta->_mappedToKey = name;
            propertyMeta->_next = mapper[name] ?: nil;
            mapper[name] = propertyMeta;
        }];
        
        if (mapper.count) _mapper = mapper;
        if (keyPathPropertyMetas) _keyPathPropertyMetas = keyPathPropertyMetas;
        if (multiKeysPropertyMetas) _multiKeysPropertyMetas = multiKeysPropertyMetas;
        
        _classInfo = classInfo;
        _keyMappedCount = _allPropertyMetas.count;
        _nsType = YYClassGetNSType(cls);
        _hasCustomWillTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomWillTransformFromDictionary:)]);
        _hasCustomTransformFromDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformFromDictionary:)]);
        _hasCustomTransformToDictionary = ([cls instancesRespondToSelector:@selector(modelCustomTransformToDictionary:)]);
        _hasCustomClassFromDictionary = ([cls respondsToSelector:@selector(modelCustomClassForDictionary:)]);
        
        return self;
    }
    
    /// Returns the cached model class meta
    /// 返回缓存 元类 模型 
    + (instancetype)metaWithClass:(Class)cls {
    
        // 传入的类型为空直接返回 nil
        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);
    
        // 获取字典缓存的数据
        _YYModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls));
        dispatch_semaphore_signal(lock);
    
        // 没有缓存数据  或者 缓存数据需要根系
        if (!meta || meta->_classInfo.needUpdate) {
    
            // 实例化  元 数据模型
            meta = [[_YYModelMeta alloc] initWithClass:cls];
            if (meta) {
                dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
                // 保存到缓存池
                CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta));
                dispatch_semaphore_signal(lock);
            }
        }
        return meta;
    }
    
    @end
    

    相关文章

      网友评论

        本文标题: YYMode ——_YYModelMeta 源码学习

        本文链接:https://www.haomeiwen.com/subject/zhyajttx.html