[iOS] YYmodel源码分析

作者: 木小易Ying | 来源:发表于2020-01-28 23:10 被阅读0次

    无聊小姐姐今天准备看下YYmodel啦~ https://github.com/ibireme/YYModel

    YYmodel主要是需要#import "NSObject+YYModel.h",也就是其实它是NSObject的一个category,我们所希望转为的model就是这里的NSObject,可以直接在model类上面用YYModel的方法得到一个model实例。

    具体用法可以参考使用介绍(https://www.jianshu.com/p/25e678fa43d3),这边会直接从yy_modelWithDictionary开始看:

    + (instancetype)yy_modelWithDictionary:(NSDictionary *)dictionary {
        if (!dictionary || dictionary == (id)kCFNull) return nil;
        if (![dictionary isKindOfClass:[NSDictionary class]]) return nil;
        
        // model类
        Class cls = [self class];
        // 得到class的一些信息
        _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:cls];
        if (modelMeta->_hasCustomClassFromDictionary) {
            cls = [cls modelCustomClassForDictionary:dictionary] ?: cls;
        }
        
        // 建一个新的object,并用dict填充属性
        NSObject *one = [cls new];
        if ([one yy_modelSetWithDictionary:dictionary]) return one;
        return nil;
    }
    

    其实看起来很简洁,我们下面就分步看一下吧~ 首先是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 dict来维护class和meta的match
            cache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
            lock = dispatch_semaphore_create(1);
        });
        // 每次对cache dict操作都先wait再signal,保证但线程访问cache
        dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
        _YYModelMeta *meta = CFDictionaryGetValue(cache, (__bridge const void *)(cls));
        dispatch_semaphore_signal(lock);
    
        // 如果meta没有缓存过,就新建一个
        if (!meta || meta->_classInfo.needUpdate) {
            meta = [[_YYModelMeta alloc] initWithClass:cls];
            if (meta) {
                // 把创建的meta缓存起来
                dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
                CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta));
                dispatch_semaphore_signal(lock);
            }
        }
        return meta;
    }
    

    关于信号量可以看一下:https://www.cnblogs.com/yajunLi/p/6274282.html,当信号量create时候初始化的数值,就是希望最大的线程数,所以这里lock = dispatch_semaphore_create(1);就是初始化了一个单线程的lock,每次对临界区操作就先wait再signal。

    这里的lock就是为了保证CFMutableDictionaryRef cache的线程安全。cache里面保存了class和meta的键值对,那么meta是神马呢?

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

    大概可以看出来这就是用于记录这个class的各种信息的一个类,例如property mapper。当最开始没有的时候都是通过class init出来的:

    - (instancetype)initWithClass:(Class)cls {
        YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls];
        if (!classInfo) return nil;
        self = [super init];
        
        // Get black list
        // 如果model实现了modelPropertyBlacklist方法,就获取一下model的modelPropertyBlacklist
        // 如果实现了该方法,则处理过程中会忽略该列表内的所有属性
        NSSet *blacklist = nil;
        if ([cls respondsToSelector:@selector(modelPropertyBlacklist)]) {
            NSArray *properties = [(id<YYModel>)cls modelPropertyBlacklist];
            if (properties) {
                blacklist = [NSSet setWithArray:properties];
            }
        }
        
        // Get white list
        // 如果model实现了modelPropertyWhitelist方法,就获取一下model的modelPropertyWhitelist
        // 如果实现了该方法,则处理过程中不会处理该列表外的属性。
        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
        // 返回容器类中的所需要存放的数据类型 (以 Class 或 Class Name 的形式)。
        // 例如@{@"shadows" : [Shadow class], @"attachments" : @"Attachment"}
        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)) {
                        // @"shadows" : [Shadow class]
                        tmp[key] = obj;
                    } else if ([obj isKindOfClass:[NSString class]]) {
                        //@"attachments" : @"Attachment"
                        Class cls = NSClassFromString(obj);
                        if (cls) {
                            tmp[key] = cls;
                        }
                    }
                }];
                // key是modelContainerPropertyGenericClass里面的key,value是class
                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) {
                if (!propertyInfo.name) continue;
                // 这里实现了黑白名单,会跳过黑名单里面的,仅保留白名单
                if (blacklist && [blacklist containsObject:propertyInfo.name]) continue;
                if (whitelist && ![whitelist containsObject:propertyInfo.name]) continue;
                
                // 获取property的meta,并且以meta.name为key,value就是meta,存入allPropertyMetas
                _YYModelPropertyMeta *meta = [_YYModelPropertyMeta metaWithClassInfo:classInfo
                                                                        propertyInfo:propertyInfo
                                                                             generic:genericMapper[propertyInfo.name]];
                if (!meta || !meta->_name) continue;
                // getter和setter都要有
                if (!meta->_getter || !meta->_setter) continue;
                if (allPropertyMetas[meta->_name]) continue;
                allPropertyMetas[meta->_name] = meta;
            }
            // 不断上询super,把父类的property也要加入
            curClassInfo = curClassInfo.superClassInfo;
        }
        if (allPropertyMetas.count) _allPropertyMetas = allPropertyMetas.allValues.copy;
        
        // create mapper
        NSMutableDictionary *mapper = [NSMutableDictionary new];
        NSMutableArray *keyPathPropertyMetas = [NSMutableArray new];
        NSMutableArray *multiKeysPropertyMetas = [NSMutableArray new];
        
        // model可以实现modelCustomPropertyMapper,返回一个 Dict,将 Model 属性名对映射到 JSON 的 Key。
        if ([cls respondsToSelector:@selector(modelCustomPropertyMapper)]) {
            NSDictionary *customMapper = [(id <YYModel>)cls modelCustomPropertyMapper];
            [customMapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyName, NSString *mappedToKey, BOOL *stop) {
                // 从allPropertyMetas里面找key也就是property name对应的meta数据,没找到也就是这个model没有这个property或者这个property没有getter&setter
                _YYModelPropertyMeta *propertyMeta = allPropertyMetas[propertyName];
                if (!propertyMeta) return;
                
                // 找到以后从allPropertyMetas里面移除这个property name的键值对
                [allPropertyMetas removeObjectForKey:propertyName];
                
                if ([mappedToKey isKindOfClass:[NSString class]]) {
                    if (mappedToKey.length == 0) return;
                    
                    // 设置这个property的meta数据的_mappedToKey为json里面的相应字段
                    propertyMeta->_mappedToKey = mappedToKey;
                    // 这一步支持了我们用.来分割json的嵌套
                    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) {
                        // 设置这个property的meta数据的_mappedToKeyPath为一个array,存了json的keypath嵌套
                        propertyMeta->_mappedToKeyPath = keyPath;
                        [keyPathPropertyMetas addObject:propertyMeta];
                    }
                    // 如果多个property对应json里的同一个字段,会被弄成链表
                    // mapper以json的字段为key,value是property meta
                    propertyMeta->_next = mapper[mappedToKey] ?: nil;
                    mapper[mappedToKey] = propertyMeta;
                    
                } else if ([mappedToKey isKindOfClass:[NSArray class]]) {
                    
                    // 如果一个property对应json里面的多个字段
                    NSMutableArray *mappedToKeyArray = [NSMutableArray new];
                    for (NSString *oneKey in ((NSArray *)mappedToKey)) {
                        if (![oneKey isKindOfClass:[NSString class]]) continue;
                        if (oneKey.length == 0) continue;
                        
                        // 这里也是区分key path和key的,可以的话就以string的形式存入mappedToKeyArray,如果是key path就存入一个array
                        NSArray *keyPath = [oneKey componentsSeparatedByString:@"."];
                        if (keyPath.count > 1) {
                            [mappedToKeyArray addObject:keyPath];
                        } else {
                            [mappedToKeyArray addObject:oneKey];
                        }
                        
                        // 设置propertyMeta的_mappedToKey和_mappedToKeyPath
                        if (!propertyMeta->_mappedToKey) {
                            propertyMeta->_mappedToKey = oneKey;
                            propertyMeta->_mappedToKeyPath = keyPath.count > 1 ? keyPath : nil;
                        }
                    }
                    if (!propertyMeta->_mappedToKey) return;
                    
                    propertyMeta->_mappedToKeyArray = mappedToKeyArray;
                    
                    // multiKeysPropertyMetas存了所有的propertyMeta
                    [multiKeysPropertyMetas addObject:propertyMeta];
                    
                    // 链表
                    propertyMeta->_next = mapper[mappedToKey] ?: nil;
                    mapper[mappedToKey] = propertyMeta;
                }
            }];
        }
        
        // 遍历剩下的不custom map的property,把这些propertyMeta的_mappedToKey就设为这个property自己的name,还用mapper存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;
    }
    

    总结一下这几个容器属性存了什么东西:

    • NSDictionary *_mapper:key是json里的key字段,value是property meta
    • NSArray *_allPropertyMetas:一个model的所有包括父类们的property meta array
    • NSArray *_keyPathPropertyMetas:对应json里面key path的property meta array
    • NSArray *_multiKeysPropertyMetas:也是存了property meta array,但是这里面的property都是一个对应多个json的keypath的

    上面其实就是我们在yy_modelWithDictionary方法里面是如何拿到了_YYModelMeta,然后执行了下面这段:

    if (modelMeta->_hasCustomClassFromDictionary) {
      cls = [cls modelCustomClassForDictionary:dictionary] ?: cls;
    }
    

    也就是如果modelMeta的_hasCustomClassFromDictionary是yes,就执行class的modelCustomClassForDictionary方法,将需要解析的dict传进去,有点类似AOP的前向切入。

    然后就真的开始填充啦:

    - (BOOL)yy_modelSetWithDictionary:(NSDictionary *)dic {
        if (!dic || dic == (id)kCFNull) return NO;
        if (![dic isKindOfClass:[NSDictionary class]]) return NO;
        
    
        _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:object_getClass(self)];
        if (modelMeta->_keyMappedCount == 0) return NO;
        
        // 这里也类似前向切入,把要解析的dict给modelCustomWillTransformFromDictionary函数告诉model即将开始反序列化,并允许model来处理一下dict,比如把不想序列化的键值对删掉
        if (modelMeta->_hasCustomWillTransformFromDictionary) {
            dic = [((id<YYModel>)self) modelCustomWillTransformFromDictionary:dic];
            if (![dic isKindOfClass:[NSDictionary class]]) return NO;
        }
        
        ModelSetContext context = {0};
        context.modelMeta = (__bridge void *)(modelMeta);
        context.model = (__bridge void *)(self);
        context.dictionary = (__bridge void *)(dic);
        
        
        // 如果mapper的key数目大于等于dic的数目
        if (modelMeta->_keyMappedCount >= CFDictionaryGetCount((CFDictionaryRef)dic)) {
            CFDictionaryApplyFunction((CFDictionaryRef)dic, ModelSetWithDictionaryFunction, &context);
            if (modelMeta->_keyPathPropertyMetas) {
                CFArrayApplyFunction((CFArrayRef)modelMeta->_keyPathPropertyMetas,
                                     CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_keyPathPropertyMetas)),
                                     ModelSetWithPropertyMetaArrayFunction,
                                     &context);
            }
            if (modelMeta->_multiKeysPropertyMetas) {
                CFArrayApplyFunction((CFArrayRef)modelMeta->_multiKeysPropertyMetas,
                                     CFRangeMake(0, CFArrayGetCount((CFArrayRef)modelMeta->_multiKeysPropertyMetas)),
                                     ModelSetWithPropertyMetaArrayFunction,
                                     &context);
            }
        } else {
            // 如果mapper的key数目小于dic的数目
           CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,
                                 CFRangeMake(0, modelMeta->_keyMappedCount),
                                 ModelSetWithPropertyMetaArrayFunction,
                                 &context);
        }
        
        // 这里是把dict传给model,让model有权决定这次的转换是不是有效
        if (modelMeta->_hasCustomTransformFromDictionary) {
            return [((id<YYModel>)self) modelCustomTransformFromDictionary:dic];
        }
        return YES;
    }
    

    这里其实最关键的就是这几个CFArrayApplyFunction是apply了什么function,干了些什么事情,所以先看下CFArrayApplyFunction是做啥的:

    // Calls a function once for each element in range in an array.
    // 类似给每个element执行一个方法
    func CFArrayApplyFunction(_ theArray: CFArray!, 
                            _ range: CFRange, 
                            _ applier: ((UnsafeRawPointer?, UnsafeMutableRawPointer?) -> Void)!, 
                            _ context: UnsafeMutableRawPointer!)
    

    遍历容器类时,选择更高效的方法相对于 Foundation 的方法来说,CoreFoundation 的方法有更高的性能,用 CFArrayApplyFunction() 和 CFDictionaryApplyFunction() 方法来遍历容器类能带来不少性能提升,但代码写起来会非常麻烦。

    性能优化部分可以参考:http://www.cocoachina.com/articles/17874 写的灰常好

    所以我们需要来看一下给各个元素执行的具体方法干了什么事情:

    // 对象以及json dict以及model meta都包装成一个context传给了function
    ModelSetContext context = {0};
    context.modelMeta = (__bridge void *)(modelMeta);
    context.model = (__bridge void *)(self);
    context.dictionary = (__bridge void *)(dic);
    
    // 给每个属性赋值
    static void ModelSetWithPropertyMetaArrayFunction(const void *_propertyMeta, void *_context) {
        ModelSetContext *context = _context;
        __unsafe_unretained NSDictionary *dictionary = (__bridge NSDictionary *)(context->dictionary);
        __unsafe_unretained _YYModelPropertyMeta *propertyMeta = (__bridge _YYModelPropertyMeta *)(_propertyMeta);
        if (!propertyMeta->_setter) return;
        id value = nil;
    
        // 一个property对应多个key
        if (propertyMeta->_mappedToKeyArray) {
            value = YYValueForMultiKeys(dictionary, propertyMeta->_mappedToKeyArray);
    
        // property对应的是keyPath,即嵌套json
        } else if (propertyMeta->_mappedToKeyPath) {
            value = YYValueForKeyPath(dictionary, propertyMeta->_mappedToKeyPath);
    
        // 正常的就直接从dict里面取值
        } else {
            value = [dictionary objectForKey:propertyMeta->_mappedToKey];
        }
        
        if (value) {
            // 赋值
            __unsafe_unretained id model = (__bridge id)(context->model);
            ModelSetValueForProperty(model, value, propertyMeta);
        }
    }
    

    这里有一个蛮好的做法,把对象放入context,然后传给static的function,这样就可以获取obj啦

    keyPath以及一个property对应多个key的值是通过下面的方式得到哒:

    /// keypath
    static force_inline id YYValueForKeyPath(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *keyPaths) {
        id value = nil;
    
        // 一层一层的读
        for (NSUInteger i = 0, max = keyPaths.count; i < max; i++) {
            value = dic[keyPaths[i]];
            if (i + 1 < max) {
                if ([value isKindOfClass:[NSDictionary class]]) {
                    dic = value;
                } else {
                    return nil;
                }
            }
        }
        return value;
    }
    
    /// 一个property对应多个key,就是按顺序看哪个key/keypath能取到值就break返回啦
    static force_inline id YYValueForMultiKeys(__unsafe_unretained NSDictionary *dic, __unsafe_unretained NSArray *multiKeys) {
        id value = nil;
        for (NSString *key in multiKeys) {
            if ([key isKindOfClass:[NSString class]]) {
                value = dic[key];
                if (value) break;
            } else {
                value = YYValueForKeyPath(dic, (NSArray *)key);
                if (value) break;
            }
        }
        return value;
    }
    

    当拿到值以后会通过ModelSetValueForProperty将value赋值给model对象相应的property。这个函数非常的长,会做很多转换,举一段小例子吧~

    static void ModelSetValueForProperty(__unsafe_unretained id model,
                                         __unsafe_unretained id value,
                                         __unsafe_unretained _YYModelPropertyMeta *meta) {
        if (meta->_isCNumber) {
            ……
        } else if (meta->_nsType) {
            if (value == (id)kCFNull) {
                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
            } else {
                switch (meta->_nsType) {
                    case YYEncodingTypeNSString:
                    case YYEncodingTypeNSMutableString: {
                        ……
                    } break;
                        
                    case YYEncodingTypeNSValue:
                    case YYEncodingTypeNSNumber:
                    case YYEncodingTypeNSDecimalNumber: {
                        ……
                    } break;
                        
                    case YYEncodingTypeNSData:
                    case YYEncodingTypeNSMutableData: {
                        ……
                    } break;
                        
                    // 如果property属性是NSDate
                    case YYEncodingTypeNSDate: {
                        // 如果value本来就是date就不用转了
                        if ([value isKindOfClass:[NSDate class]]) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
    
                        // 如果value是string就转成date
                        } else if ([value isKindOfClass:[NSString class]]) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSDateFromString(value));
                        }
                    } break;
                        
                    case YYEncodingTypeNSURL: {
                        ……
                    } break;
                        
                    // 如果property的属性是NSArray或者mutable array
                    case YYEncodingTypeNSArray:
                    case YYEncodingTypeNSMutableArray: {
    
                        // meta->_genericCls就是这个property对应的class,之前在modelContainerPropertyGenericClass方法提供的dict里面,以property名字为key,class为value
                        // 如果容器的element是比较特殊的类
                        if (meta->_genericCls) {
                            NSArray *valueArr = nil;
                            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]) {
                                        [objectArr addObject:one];
                                    // 如果value element还不是这个类就转换一下
                                    } else if ([one isKindOfClass:[NSDictionary class]]) {
                                        Class cls = meta->_genericCls;
                                        // 会先执行modelCustomClassForDictionary把这个element传进去,如果响应了就用返回的class,如果没有则用之前的指定class
                                        if (meta->_hasCustomClassFromDictionary) {
                                            cls = [cls modelCustomClassForDictionary:one];
                                            if (!cls) cls = meta->_genericCls; // for xcode code coverage
                                        }
                                        // 最后用class new一个object,然后通过value给这个新的obj赋值即可
                                        NSObject *newOne = [cls new];
                                        [newOne yy_modelSetWithDictionary:one];
                                        if (newOne) [objectArr addObject:newOne];
                                    }
                                }
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, objectArr);
                            }
                        } else {
                            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);
                                }
    
                            // 如果value是set,需要转成array或者mutable array
                            } else if ([value isKindOfClass:[NSSet class]]) {
                                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: {
                        ……
                    } break;
                        
                    case YYEncodingTypeNSSet:
                    case YYEncodingTypeNSMutableSet: {
                        ……
                    } // break; commented for code coverage in next line
                        
                    default: break;
                }
            }
        } else {
            ……
        }
    }
    

    上面这一段其实就是YYmodel比较独有的自动转换,会根据property的类型把json里面拿到的value适当的做转换。

    最后总结一下YYmodel的反序列化,它会给每个类建一个meta数据类,这个里面存了很多array之类的,array里面会有一些property的meta类,然后转换的时候会遍历property,从json里面去读值赋给property。整体非常简洁所以其实YYmodel的代码也不多,但是非常厉害吖~

    感觉我又水了一篇。。如果你看到了这里我感到非常抱歉。。sorry 0.0

    相关文章

      网友评论

        本文标题:[iOS] YYmodel源码分析

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