• 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对象。

  • 相关阅读:
    项目管理软件选择:redmine or JIRA
    为已编译的DLL附带强命名
    NET简单的一个画图程序
    公共的Json操作类
    ASP.NET 程序优化
    提高ASP.NET页面载入速度的方法
    DataTable快速定制之Expression属性表达式
    TCP和UDP Client 代码
    Jquery实现异步上传图片
    C语言Socket编程(计算机网络作业)
  • 原文地址:https://www.cnblogs.com/coolcold/p/12044551.html
Copyright © 2020-2023  润新知