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

 

 

 

 

 

posted @ 2019-12-15 16:26  do+better  阅读(474)  评论(0编辑  收藏  举报