zoukankan      html  css  js  c++  java
  • YYModel 源码分析

    + (instancetype)yy_modelWithDictionary:(NSDictionary *)dictionary {

        if (!dictionary || dictionary == (id)kCFNull) return nil;

        if (![dictionary isKindOfClass:[NSDictionary class]]) return nil;

        

        Class cls = [self class];

        _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:cls];

        if (modelMeta->_hasCustomClassFromDictionary) {

            cls = [cls modelCustomClassForDictionary:dictionary] ?: cls;

        }

          

        NSObject *one = [cls new];

        if ([one yy_modelSetWithDictionary:dictionary]) return one;

        return nil;

    }

    第一步: 准备_YYModelMeta 类:

    分析:

    1. cache缓存 _YYModelMeta 类,如果一个模型已经转换过,就会存储到cache里面,如果下次遇到相同的model,就会直接从缓存中取,不会重新创建,因为模型转换频率较高,所以优化非常有必要,体现了框架设计者的良苦用心:

    2. 如果缓存中没有,meta = [[_YYModelMeta alloc] initWithClass:cls]; 创建_YYModelMeta类:

     

    /// Returns the cached model class meta

    + (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);

        _YYModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls));

        dispatch_semaphore_signal(lock);

        if (!meta || meta->_classInfo.needUpdate) {

            meta = [[_YYModelMeta alloc] initWithClass:cls];

            if (meta) {

                dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);

                CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta));

                dispatch_semaphore_signal(lock);

            }

        }

        return meta;

    }

    - (instancetype)initWithClass:(Class)cls {

        YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls];

        if (!classInfo) return nil;

        self = [super init];

        

       检查黑名单(哪些不用处理),白名单,为了提高性能。

        // Get black list

        NSSet *blacklist = nil;

        if ([cls respondsToSelector:@selector(modelPropertyBlacklist)]) {

            NSArray *properties = [(id<YYModel>)cls modelPropertyBlacklist];

            if (properties) {

                blacklist = [NSSet setWithArray:properties];

            }

        }

        

        // Get white list

        NSSet *whitelist = nil;

        if ([cls respondsToSelector:@selector(modelPropertyWhitelist)]) {

            NSArray *properties = [(id<YYModel>)cls modelPropertyWhitelist];

            if (properties) {

                whitelist = [NSSet setWithArray:properties];

            }

        }

        

       是否需要属性替换

        // Get container property's generic class

        NSDictionary *genericMapper = nil;

        if ([cls respondsToSelector:@selector(modelContainerPropertyGenericClass)]) {

            genericMapper = [(id<YYModel>)cls modelContainerPropertyGenericClass];

            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;

            }

        }

        

      把父类子类的所有属性放到map里面去

        // 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) {

                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;

    }

    第二部: 新建cls类对象one。

    第三部: 根据dictionary转换one对象。

  • 相关阅读:
    rest framework 认证 权限 频率
    rest framework 视图,路由
    rest framework 序列化
    10.3 Vue 路由系统
    10.4 Vue 父子传值
    10.2 Vue 环境安装
    10.1 ES6 的新增特性以及简单语法
    Django 跨域请求处理
    20190827 On Java8 第十四章 流式编程
    20190825 On Java8 第十三章 函数式编程
  • 原文地址:https://www.cnblogs.com/coolcold/p/12044551.html
Copyright © 2011-2022 走看看