美文网首页
YYKit__YYModel_源码分析

YYKit__YYModel_源码分析

作者: sea777777 | 来源:发表于2016-09-09 17:33 被阅读400次
    • 大概流程:把数据源json对象转成dictionary,创建YYModelMeta类,YYModelMeta类含有_mapper属性,_mapper属性(Key:属性的名字, Value:_YYModelPropertyMeta.),然后遍历dictionary,每次遍历调用根据_mapper寻找到对应的_YYModelPropertyMeta,调用_YYModelPropertyMeta的setter方法,把dictionary的value值设置到model里。

    • 注:YYModel是对NSObject的扩展,所以在创建model实例时,根据runtime能遍历出实例model 的属性 方法 等等;

    • Apple said:
      The top level object is an NSArray or NSDictionary.
      All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
      All dictionary keys are instances of NSString.
      Numbers are not NaN or infinity.

    • 先说下两个容易混淆的概念: property 和 attribute,翻译过来都是属性的意思:

    • objc_property_t是表示Objective-C声明的属性的类型,其实际是指向objc_property结构体的指针,其定义如下:
      typedef struct objc_property *objc_property_t;
      objc_property_attribute_t定义了属性的特性(attribute),如:Readonly,Retain,Nonatomic,Dynamic,Weak,它是一个结构体,定义如下:

    /// Defines a property attribute
    
    typedef struct {
        const char *name;           /**< The name of the attribute */
        const char *value;          /**< The value of the attribute (usually empty) */
    } objc_property_attribute_t;
    

    下面看NSObject+YYModel.m这个类:
    以下的方法都是NSObject+YYModel.m类的内部方法

    + (instancetype)modelWithJSON:(id)json {
    
        NSDictionary *dic = [self _yy_dictionaryWithJSON:json];
        return [self modelWithDictionary:dic];
    }
    
    //把json 转换成字典
    + (NSDictionary *)_yy_dictionaryWithJSON:(id)json {
        if (!json || json == (id)kCFNull) return nil;
        NSDictionary *dic = nil;
        NSData *jsonData = nil;
        if ([json isKindOfClass:[NSDictionary class]]) {
            dic = json;
        } else if ([json isKindOfClass:[NSString class]]) {
            jsonData = [(NSString *)json dataUsingEncoding : NSUTF8StringEncoding];
        } else if ([json isKindOfClass:[NSData class]]) {
            jsonData = json;
        }
        if (jsonData) {
            dic = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:NULL];
            if (![dic isKindOfClass:[NSDictionary class]]) dic = nil;
        }
        return dic;
    }
    
    //返回值为instancetype ,类似泛型
    + (instancetype)modelWithDictionary:(NSDictionary *)dictionary {
        if (!dictionary || dictionary == (id)kCFNull) return nil;
        if (![dictionary isKindOfClass:[NSDictionary class]]) return nil;
        
        
        //这个cls是当前类,如Book  Person
        Class cls = [self class];
        _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:cls];
        
        //如果实现了modelCustomClassForDictionary方法,则进行调用
        if (modelMeta->_hasCustomClassFromDictionary) {
            cls = [cls modelCustomClassForDictionary:dictionary] ?: cls;
        }
        
        //创建当前类的实例,并给属性赋值
        NSObject *one = [cls new];
        if ([one modelSetWithDictionary:dictionary]) return one;
        return nil;
    }
    
    //向model的属性赋值
    
    - (BOOL)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;//如果model的属性个数为0,则返回失败
       
        
        //如果实现了 CustomWillTransformFromDictionary(字典转model) 方法,则调用
        if (modelMeta->_hasCustomWillTransformFromDictionary) {
            //再转换成model之前,对json/dic 进行修改
            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);
        
        
        /*关键代码:
            如果‘元’model的属性数量   >=   赋值的属性数量(这个dic可能在转换model之前就被增加或者减少了)
            属性赋值;
         **/
        if (modelMeta->_keyMappedCount >= CFDictionaryGetCount((CFDictionaryRef)dic)) {
            
            /**属性赋值;
                将dic的key value作为参数传递给ModelSetWithDictionaryFunction,并调用ModelSetWithDictionaryFunction方法,context作为附加参数
                这个方法根据dic的key的数量,会调用多次ModelSetWithDictionaryFunction方法
             **/
            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 {
            CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,
                                 CFRangeMake(0, modelMeta->_keyMappedCount),
                                 ModelSetWithPropertyMetaArrayFunction,
                                 &context);
        }
        
        
        //如果实现了modelCustomTransformFromDictionary 方法,则调用
        if (modelMeta->_hasCustomTransformFromDictionary) {
            return [((id<YYModel>)self) modelCustomTransformFromDictionary:dic];
        }
        return YES;
    }
    
    这个是比较关键的一个方法
    
    /**
    
     Apply function for dictionary, to set the key-value pair to model.
     
     @param _key     should not be nil, NSString.
     @param _value   should not be nil.
     @param _context _context.modelMeta and _context.model should not be nil.
     */
    //这个复制方法会调用多次,每个k/v键值对都会调用一次
    static void ModelSetWithDictionaryFunction(const void *_key, const void *_value, void *_context) {
        ModelSetContext *context = _context;
    
        __unsafe_unretained _YYModelMeta *meta = (__bridge _YYModelMeta *)(context->modelMeta);
        
        //取出元类存放的key值对应的属性元类:PropertyMeta
        __unsafe_unretained _YYModelPropertyMeta *propertyMeta = [meta->_mapper objectForKey:(__bridge id)(_key)];
        
        //context->model 即 self(self作为返回值)
        __unsafe_unretained id model = (__bridge id)(context->model);
        
        
        while (propertyMeta) {
            if (propertyMeta->_setter) {
                
                //属性赋值操作,propertyMeta用来判断属性的类型
                ModelSetValueForProperty(model, (__bridge __unsafe_unretained id)_value, propertyMeta);
            }
            propertyMeta = propertyMeta->_next;
        };
    }
    
    0AB8C129-1D2E-4203-9D5C-0EA9FE8FEED5.jpg
    /**
    
     Set value to model with a property meta.
     
     @discussion Caller should hold strong reference to the parameters before this function returns.
     
     @param model Should not be nil.
     @param value Should not be nil, but can be NSNull.
     @param meta  Should not be nil, and meta->_setter should not be nil.
     */
    
    //赋值方法   对属性的元类型进行判断,但是也要对value的真实类型进行判断,并把value强转成元类的类型
    static void ModelSetValueForProperty(__unsafe_unretained id model,
                                         __unsafe_unretained id value,
                                         __unsafe_unretained _YYModelPropertyMeta *meta)
    {
        
        //如果是c number type
        if (meta->_isCNumber) {
            NSNumber *num = YYNSNumberCreateFromID(value);
            ModelSetNumberToProperty(model, num, meta);
            if (num) [num class]; // hold the number
        } 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: {
                        if ([value isKindOfClass:[NSString class]]) {
                            if (meta->_nsType == YYEncodingTypeNSString) {
                                
                                //运行时,执行model的setter方法,向model的属性赋值value
                                ((void (*)(id, SEL, id)) objc_msgSend)((id)model, meta->_setter, value);
                            } else {
                                //同上,这个参数是YYEncodingTypeNSMutableString类型
                                ((void (*)(id, SEL, id)) objc_msgSend)((id)model, meta->_setter, ((NSString *)value).mutableCopy);
                            }
                        } else if ([value isKindOfClass:[NSNumber class]]) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
                                                                           meta->_setter,
                                                                           (meta->_nsType == YYEncodingTypeNSString) ?
                                                                           ((NSNumber *)value).stringValue :
                                                                           ((NSNumber *)value).stringValue.mutableCopy);
                        } else if ([value isKindOfClass:[NSData class]]) {
                            NSMutableString *string = [[NSMutableString alloc] initWithData:value encoding:NSUTF8StringEncoding];
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, string);
                        } else if ([value isKindOfClass:[NSURL class]]) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
                                                                           meta->_setter,
                                                                           (meta->_nsType == YYEncodingTypeNSString) ?
                                                                           ((NSURL *)value).absoluteString :
                                                                           ((NSURL *)value).absoluteString.mutableCopy);
                        } else if ([value isKindOfClass:[NSAttributedString class]]) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
                                                                           meta->_setter,
                                                                           (meta->_nsType == YYEncodingTypeNSString) ?
                                                                           ((NSAttributedString *)value).string :
                                                                           ((NSAttributedString *)value).string.mutableCopy);
                        }
                    } break;
                        
                    case YYEncodingTypeNSValue:
                    case YYEncodingTypeNSNumber:
                    case YYEncodingTypeNSDecimalNumber: {
                        if (meta->_nsType == YYEncodingTypeNSNumber) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSNumberCreateFromID(value));
                        } else if (meta->_nsType == YYEncodingTypeNSDecimalNumber) {
                            if ([value isKindOfClass:[NSDecimalNumber class]]) {
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
                            } else if ([value isKindOfClass:[NSNumber class]]) {
                                NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithDecimal:[((NSNumber *)value) decimalValue]];
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, decNum);
                            } else if ([value isKindOfClass:[NSString class]]) {
                                NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithString:value];
                                NSDecimal dec = decNum.decimalValue;
                                if (dec._length == 0 && dec._isNegative) {
                                    decNum = nil; // NaN
                                }
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, decNum);
                            }
                        } else { // YYEncodingTypeNSValue
                            if ([value isKindOfClass:[NSValue class]]) {
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
                            }
                        }
                    } break;
                        
                    case YYEncodingTypeNSData:
                    case YYEncodingTypeNSMutableData: {
                        if ([value isKindOfClass:[NSData class]]) {
                            if (meta->_nsType == YYEncodingTypeNSData) {
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
                            } else {
                                NSMutableData *data = ((NSData *)value).mutableCopy;
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, data);
                            }
                        } else if ([value isKindOfClass:[NSString class]]) {
                            NSData *data = [(NSString *)value dataUsingEncoding:NSUTF8StringEncoding];
                            if (meta->_nsType == YYEncodingTypeNSMutableData) {
                                data = ((NSData *)data).mutableCopy;
                            }
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, data);
                        }
                    } break;
                        
                    case YYEncodingTypeNSDate: {
                        if ([value isKindOfClass:[NSDate class]]) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
                        } else if ([value isKindOfClass:[NSString class]]) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, YYNSDateFromString(value));
                        }
                    } break;
                        
                    case YYEncodingTypeNSURL: {
                        if ([value isKindOfClass:[NSURL class]]) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
                        } else if ([value isKindOfClass:[NSString class]]) {
                            NSCharacterSet *set = [NSCharacterSet whitespaceAndNewlineCharacterSet];
                            NSString *str = [value stringByTrimmingCharactersInSet:set];
                            if (str.length == 0) {
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, nil);
                            } else {
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, [[NSURL alloc] initWithString:str]);
                            }
                        }
                    } break;
                        
                    case YYEncodingTypeNSArray:
                    case YYEncodingTypeNSMutableArray: {
                        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];
                                    } else if ([one isKindOfClass:[NSDictionary class]]) {
                                        Class cls = meta->_genericCls;
                                        if (meta->_hasCustomClassFromDictionary) {
                                            cls = [cls modelCustomClassForDictionary:one];
                                            if (!cls) cls = meta->_genericCls; // for xcode code coverage
                                        }
                                        NSObject *newOne = [cls new];
                                        [newOne 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);
                                }
                            } 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: {
                        if ([value isKindOfClass:[NSDictionary class]]) {
                            if (meta->_genericCls) {
                                NSMutableDictionary *dic = [NSMutableDictionary new];
                                [((NSDictionary *)value) enumerateKeysAndObjectsUsingBlock:^(NSString *oneKey, id oneValue, BOOL *stop) {
                                    if ([oneValue isKindOfClass:[NSDictionary class]]) {
                                        Class cls = meta->_genericCls;
                                        if (meta->_hasCustomClassFromDictionary) {
                                            cls = [cls modelCustomClassForDictionary:oneValue];
                                            if (!cls) cls = meta->_genericCls; // for xcode code coverage
                                        }
                                        NSObject *newOne = [cls new];
                                        [newOne modelSetWithDictionary:(id)oneValue];
                                        if (newOne) dic[oneKey] = newOne;
                                    }
                                }];
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, dic);
                            } else {
                                if (meta->_nsType == YYEncodingTypeNSDictionary) {
                                    ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
                                } else {
                                    ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
                                                                                   meta->_setter,
                                                                                   ((NSDictionary *)value).mutableCopy);
                                }
                            }
                        }
                    } break;
                        
                    case YYEncodingTypeNSSet:
                    case YYEncodingTypeNSMutableSet: {
                        NSSet *valueSet = nil;
                        if ([value isKindOfClass:[NSArray class]]) valueSet = [NSMutableSet setWithArray:value];
                        else if ([value isKindOfClass:[NSSet class]]) valueSet = ((NSSet *)value);
                        
                        if (meta->_genericCls) {
                            NSMutableSet *set = [NSMutableSet new];
                            for (id one in valueSet) {
                                if ([one isKindOfClass:meta->_genericCls]) {
                                    [set addObject:one];
                                } else if ([one isKindOfClass:[NSDictionary class]]) {
                                    Class cls = meta->_genericCls;
                                    if (meta->_hasCustomClassFromDictionary) {
                                        cls = [cls modelCustomClassForDictionary:one];
                                        if (!cls) cls = meta->_genericCls; // for xcode code coverage
                                    }
                                    NSObject *newOne = [cls new];
                                    [newOne modelSetWithDictionary:one];
                                    if (newOne) [set addObject:newOne];
                                }
                            }
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, set);
                        } else {
                            if (meta->_nsType == YYEncodingTypeNSSet) {
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, valueSet);
                            } else {
                                ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model,
                                                                               meta->_setter,
                                                                               ((NSSet *)valueSet).mutableCopy);
                            }
                        }
                    } // break; commented for code coverage in next line
                        
                    default: break;
                }
            }
        } else {
            BOOL isNull = (value == (id)kCFNull);
            switch (meta->_type & YYEncodingTypeMask) {
                case YYEncodingTypeObject: {
                    if (isNull) {
                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)nil);
                    } else if ([value isKindOfClass:meta->_cls] || !meta->_cls) {
                        ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)value);
                    } else if ([value isKindOfClass:[NSDictionary class]]) {
                        NSObject *one = nil;
                        if (meta->_getter) {
                            one = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, meta->_getter);
                        }
                        if (one) {
                            [one modelSetWithDictionary:value];
                        } else {
                            Class cls = meta->_cls;
                            if (meta->_hasCustomClassFromDictionary) {
                                cls = [cls modelCustomClassForDictionary:value];
                                if (!cls) cls = meta->_genericCls; // for xcode code coverage
                            }
                            one = [cls new];
                            [one modelSetWithDictionary:value];
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, (id)one);
                        }
                    }
                } break;
                    
                case YYEncodingTypeClass: {
                    if (isNull) {
                        ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)NULL);
                    } else {
                        Class cls = nil;
                        if ([value isKindOfClass:[NSString class]]) {
                            cls = NSClassFromString(value);
                            if (cls) {
                                ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)cls);
                            }
                        } else {
                            cls = object_getClass(value);
                            if (cls) {
                                if (class_isMetaClass(cls)) {
                                    ((void (*)(id, SEL, Class))(void *) objc_msgSend)((id)model, meta->_setter, (Class)value);
                                }
                            }
                        }
                    }
                } break;
                    
                case  YYEncodingTypeSEL: {
                    if (isNull) {
                        ((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)NULL);
                    } else if ([value isKindOfClass:[NSString class]]) {
                        SEL sel = NSSelectorFromString(value);
                        if (sel) ((void (*)(id, SEL, SEL))(void *) objc_msgSend)((id)model, meta->_setter, (SEL)sel);
                    }
                } break;
                    
                case YYEncodingTypeBlock: {
                    if (isNull) {
                        ((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())NULL);
                    } else if ([value isKindOfClass:YYNSBlockClass()]) {
                        ((void (*)(id, SEL, void (^)()))(void *) objc_msgSend)((id)model, meta->_setter, (void (^)())value);
                    }
                } break;
                    
                case YYEncodingTypeStruct:
                case YYEncodingTypeUnion:
                case YYEncodingTypeCArray: {
                    if ([value isKindOfClass:[NSValue class]]) {
                        const char *valueType = ((NSValue *)value).objCType;
                        const char *metaType = meta->_info.typeEncoding.UTF8String;
                        if (valueType && metaType && strcmp(valueType, metaType) == 0) {
                            [model setValue:value forKey:meta->_name];
                        }
                    }
                } break;
                    
                case YYEncodingTypePointer:
                case YYEncodingTypeCString: {
                    if (isNull) {
                        ((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, (void *)NULL);
                    } else if ([value isKindOfClass:[NSValue class]]) {
                        NSValue *nsValue = value;
                        if (nsValue.objCType && strcmp(nsValue.objCType, "^v") == 0) {
                            ((void (*)(id, SEL, void *))(void *) objc_msgSend)((id)model, meta->_setter, nsValue.pointerValue);
                        }
                    }
                } // break; commented for code coverage in next line
                    
                default: break;
            }
        }
    }
    
    
    
    //上下文,存放model元类信息,model->self, 需要转化的字典数据
    
    typedef struct {
        void *modelMeta;  ///< _YYModelMeta
        void *model;      ///< id (self)
        void *dictionary; ///< NSDictionary (json)
    } ModelSetContext;
    
    + (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);
                //存储缓存,key:当前类,value:mete元类
                //对于多个同样class类型的实例,不会重复缓存
                //缓存会提高效率,不用每次都创建mode元类,节省内存
                CFDictionarySetValue(cache, (__bridge const void *)(cls), (__bridge const void *)(meta));
                //解锁
                dispatch_semaphore_signal(lock);
            }
        }
        return meta;
    }
    
    //创建modelMete类
    - (instancetype)initWithClass:(Class)cls {
        YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls];
        if (!classInfo) return nil;
        self = [super init];
        
        // Get black list
        NSSet *blacklist = nil;
        //如果响应了modelPropertyBlacklist方法,则存储黑名单
        if ([cls respondsToSelector:@selector(modelPropertyBlacklist)]) {
            NSArray *properties = [(id<YYModel>)cls modelPropertyBlacklist];
            if (properties) {
                blacklist = [NSSet setWithArray:properties];
            }
        }
        
        // Get white list
        NSSet *whitelist = nil;
        //如果响应了modelPropertyWhitelist方法,则存储白名单
        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;
            }
        }
        
        //保存属性元类
        NSMutableDictionary *allPropertyMetas = [NSMutableDictionary new];
        YYClassInfo *curClassInfo = classInfo;
        NSLog(@"curClassInfo.propertyInfos:%@",curClassInfo.description);
        //递归解析,遍历classInfo类的所有属性,过滤掉黑名单,白名单没有的也过滤掉
        while (curClassInfo && curClassInfo.superCls != nil) {
            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;
        }
        
        //,如果元类属性mete存在,则存储所有的属性元类
        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) {
                
                //取出自定义的PropertyMetas
                _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存储的key是映射后的key
                    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;
                }
            }];
        }
        
        
        //遍历所有属性集合,存储mapper,key值:属性名字     value值:属性元类
        [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;
    }
    
     NSLog(@"++++++++++++++++++%s",class_getName(cls));
        _superCls = class_getSuperclass(cls);
        _isMeta = class_isMetaClass(cls);
        if (!_isMeta) {
            _metaCls = objc_getMetaClass(class_getName(cls));
        }
        _name = NSStringFromClass(cls);
        [self _update];
    
        _superClassInfo = [self.class classInfoWithClass:_superCls];
        return self;
    }
    
    //记录类的所有变量、方法、属性
    //以键值对的方式进行存储,key:方法、变量、属性的名称,是string类型,  value:变量、方法、属性列表
    - (void)_update {
        _ivarInfos = nil;
        _methodInfos = nil;
        _propertyInfos = nil;
        
        Class cls = self.cls;
        unsigned int methodCount = 0;
        
        //运行时,存储方法列表
        Method *methods = class_copyMethodList(cls, &methodCount);
        if (methods) {
            NSMutableDictionary *methodInfos = [NSMutableDictionary new];
            _methodInfos = methodInfos;
            for (unsigned int i = 0; i < methodCount; i++) {
                YYClassMethodInfo *info = [[YYClassMethodInfo alloc] initWithMethod:methods[i]];
                if (info.name) methodInfos[info.name] = info;
            }
            free(methods);
        }
        
        
        //存储属性列表
        unsigned int propertyCount = 0;
        objc_property_t *properties = class_copyPropertyList(cls, &propertyCount);
        if (properties) {
            NSMutableDictionary *propertyInfos = [NSMutableDictionary new];
            _propertyInfos = propertyInfos;
            for (unsigned int i = 0; i < propertyCount; i++) {
                YYClassPropertyInfo *info = [[YYClassPropertyInfo alloc] initWithProperty:properties[i]];
                if (info.name) propertyInfos[info.name] = info;
            }
            free(properties);
        }
        
        
        //存储变量列表
        unsigned int ivarCount = 0;
        Ivar *ivars = class_copyIvarList(cls, &ivarCount);
        if (ivars) {
            NSMutableDictionary *ivarInfos = [NSMutableDictionary new];
            _ivarInfos = ivarInfos;
            for (unsigned int i = 0; i < ivarCount; i++) {
                YYClassIvarInfo *info = [[YYClassIvarInfo alloc] initWithIvar:ivars[i]];
                if (info.name) ivarInfos[info.name] = info;
            }
            free(ivars);
        }
        
        if (!_ivarInfos) _ivarInfos = @{};
        if (!_methodInfos) _methodInfos = @{};
        if (!_propertyInfos) _propertyInfos = @{};
        
        _needUpdate = NO;
    }
    
    - (instancetype)initWithMethod:(Method)method {
        if (!method) return nil;
        self = [super init];
        _method = method;
        _sel = method_getName(method);
        _imp = method_getImplementation(method);
        const char *name = sel_getName(_sel);
        if (name) {
            _name = [NSString stringWithUTF8String:name];
        }
        const char *typeEncoding = method_getTypeEncoding(method);
        if (typeEncoding) {
            
            //存储参数+返回值 的 string类型.c12@0:4#8  ,#8@0:4 ,v16@0:4Q8
            _typeEncoding = [NSString stringWithUTF8String:typeEncoding];
        }
        char *returnType = method_copyReturnType(method);
        if (returnType) {
            
            //存储返回值的类型,如:Vv   ,c   ,@   等......
            _returnTypeEncoding = [NSString stringWithUTF8String:returnType];
            free(returnType);
        }
        
        //获取参数的数量
        unsigned int argumentCount = method_getNumberOfArguments(method);
        if (argumentCount > 0) {
            NSMutableArray *argumentTypes = [NSMutableArray new];
            for (unsigned int i = 0; i < argumentCount; i++) {
                
                //获取参数的类型
                char *argumentType = method_copyArgumentType(method, i);
                NSString *type = argumentType ? [NSString stringWithUTF8String:argumentType] : nil;
                [argumentTypes addObject:type ? type : @""];
                if (argumentType) free(argumentType);
            }
            _argumentTypeEncodings = argumentTypes;
        }
        return self;
    }
    
    - (instancetype)initWithProperty:(objc_property_t)property {
        if (!property) return nil;
        self = [super init];
        _property = property;
        const char *name = property_getName(property);
        if (name) {
            _name = [NSString stringWithUTF8String:name];
        }
        
        //记录属性Attribute
        //Attribute 是描述property的结构体
        //定义如下:
        //    typedef struct {
        //        const char *name;           // 特性名
        //        const char *value;          // 特性值
        //    } objc_property_attribute_t;
        
        
        YYEncodingType type = 0;
        unsigned int attrCount;
        objc_property_attribute_t *attrs = property_copyAttributeList(property, &attrCount);
        for (unsigned int i = 0; i < attrCount; i++) {
            switch (attrs[i].name[0]) {
                case 'T': { // Type encoding
                    if (attrs[i].value) {
                        _typeEncoding = [NSString stringWithUTF8String:attrs[i].value];
                        type = YYEncodingGetType(attrs[i].value);
                        
                        if ((type & YYEncodingTypeMask) == YYEncodingTypeObject && _typeEncoding.length) {
                            NSScanner *scanner = [NSScanner scannerWithString:_typeEncoding];
                            if (![scanner scanString:@"@\"" intoString:NULL]) continue;
                            
                            NSString *clsName = nil;
                            if ([scanner scanUpToCharactersFromSet: [NSCharacterSet characterSetWithCharactersInString:@"\"<"] intoString:&clsName]) {
                                if (clsName.length) _cls = objc_getClass(clsName.UTF8String);
                            }
                            
                            NSMutableArray *protocols = nil;
                            while ([scanner scanString:@"<" intoString:NULL]) {
                                NSString* protocol = nil;
                                if ([scanner scanUpToString:@">" intoString: &protocol]) {
                                    if (protocol.length) {
                                        if (!protocols) protocols = [NSMutableArray new];
                                        [protocols addObject:protocol];
                                    }
                                }
                                [scanner scanString:@">" intoString:NULL];
                            }
                            _protocols = protocols;
                        }
                    }
                } break;
                case 'V': { // Instance variable
                    if (attrs[i].value) {
                        _ivarName = [NSString stringWithUTF8String:attrs[i].value];
                    }
                } break;
                case 'R': {
                    type |= YYEncodingTypePropertyReadonly;
                } break;
                case 'C': {
                    type |= YYEncodingTypePropertyCopy;
                } break;
                case '&': {
                    type |= YYEncodingTypePropertyRetain;
                } break;
                case 'N': {
                    type |= YYEncodingTypePropertyNonatomic;
                } break;
                case 'D': {
                    type |= YYEncodingTypePropertyDynamic;
                } break;
                case 'W': {
                    type |= YYEncodingTypePropertyWeak;
                } break;
                case 'G': {
                    type |= YYEncodingTypePropertyCustomGetter;
                    if (attrs[i].value) {
                        _getter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
                    }
                } break;
                case 'S': {
                    type |= YYEncodingTypePropertyCustomSetter;
                    if (attrs[i].value) {
                        _setter = NSSelectorFromString([NSString stringWithUTF8String:attrs[i].value]);
                    }
                } // break; commented for code coverage in next line
                default: break;
            }
        }
        if (attrs) {
            free(attrs);
            attrs = NULL;
        }
        
        _type = type;
        if (_name.length) {
            if (!_getter) {
                //getter方法和属性名相同
                _getter = NSSelectorFromString(_name);
            }
            if (!_setter) {
                //如果没有实现setter方法,则创建:set+属性名首字母大写+其他字母小写 ,如  setName
                _setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [_name substringToIndex:1].uppercaseString, [_name substringFromIndex:1]]);
            }
        }
        return self;
    }
    
    /**
     Returns a valid JSON object (NSArray/NSDictionary/NSString/NSNumber/NSNull), 
     or nil if an error occurs.
     
     @param model Model, can be nil.
     @return JSON object, nil if an error occurs.
        递归
     */
    static id ModelToJSONObjectRecursive(NSObject *model) {
    
        //以下大部分工作都是验证model属性值的正确性,如果不符合规则就进行转换
        if (!model || model == (id)kCFNull) return model;
        if ([model isKindOfClass:[NSString class]]) return model;
        if ([model isKindOfClass:[NSNumber class]]) return model;
        if ([model isKindOfClass:[NSDictionary class]]) {
            
            //如果是可用的json,则返回
            if ([NSJSONSerialization isValidJSONObject:model]) return model;
            NSMutableDictionary *newDic = [NSMutableDictionary new];
            
            //如果是不可用json,则把字典拆开,再拼装
            [((NSDictionary *)model) enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
                NSString *stringKey = [key isKindOfClass:[NSString class]] ? key : key.description;
                if (!stringKey) return;
                id jsonObj = ModelToJSONObjectRecursive(obj);
                if (!jsonObj) jsonObj = (id)kCFNull;
                newDic[stringKey] = jsonObj;
            }];
            return newDic;
        }
        
        
        if ([model isKindOfClass:[NSSet class]]) {
            NSArray *array = ((NSSet *)model).allObjects;
            if ([NSJSONSerialization isValidJSONObject:array]) return array;
            NSMutableArray *newArray = [NSMutableArray new];
            for (id obj in array) {
                if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
                    [newArray addObject:obj];
                } else {
                    id jsonObj = ModelToJSONObjectRecursive(obj);
                    if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
                }
            }
            return newArray;
        }
        if ([model isKindOfClass:[NSArray class]]) {
            if ([NSJSONSerialization isValidJSONObject:model]) return model;
            NSMutableArray *newArray = [NSMutableArray new];
            for (id obj in (NSArray *)model) {
                if ([obj isKindOfClass:[NSString class]] || [obj isKindOfClass:[NSNumber class]]) {
                    [newArray addObject:obj];
                } else {
                    id jsonObj = ModelToJSONObjectRecursive(obj);
                    if (jsonObj && jsonObj != (id)kCFNull) [newArray addObject:jsonObj];
                }
            }
            return newArray;
        }
        if ([model isKindOfClass:[NSURL class]]) return ((NSURL *)model).absoluteString;
        if ([model isKindOfClass:[NSAttributedString class]]) return ((NSAttributedString *)model).string;
        if ([model isKindOfClass:[NSDate class]]) return [YYISODateFormatter() stringFromDate:(id)model];
        if ([model isKindOfClass:[NSData class]]) return nil;
        
        
        _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:[model class]];
        if (!modelMeta || modelMeta->_keyMappedCount == 0) return nil;
        
        //result 作为返回值:以下操作是向这个返回值中添加数据,key是model的键值,value是经过验证和转化后的value值
        NSMutableDictionary *result = [[NSMutableDictionary alloc] initWithCapacity:64];
        
        //dic指向了result,所以下面填充dic的内容,也就是填充了result的内容,作为返回值
        //这里返回值作为一个字典, “字典、数组都是一个可用的json类”
        __unsafe_unretained NSMutableDictionary *dic = result; // avoid retain and release in block
        
        [modelMeta->_mapper enumerateKeysAndObjectsUsingBlock:^(NSString *propertyMappedKey, _YYModelPropertyMeta *propertyMeta, BOOL *stop) {
            if (!propertyMeta->_getter) return;
            id value = nil;
    
            //如果是c number类型
            if (propertyMeta->_isCNumber) {
                value = ModelCreateNumberFromProperty(model, propertyMeta);
                
                //基本类型  如 number   string  int 等
            } else if (propertyMeta->_nsType) {
                id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
                value = ModelToJSONObjectRecursive(v);
            } else {
                
                //自定义属性类型:比基本类型更复杂,几乎包含了所有类型,如 YYEncodingTypeStruct YYEncodingTypeCArray YYEncodingTypeFloat 等
                switch (propertyMeta->_type & YYEncodingTypeMask) {
                    //id类型
                    case YYEncodingTypeObject: {
                        id v = ((id (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
                        value = ModelToJSONObjectRecursive(v);
                        if (value == (id)kCFNull) value = nil;
                    } break;
                    //Class类型
                    case YYEncodingTypeClass: {
                        Class v = ((Class (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
                        value = v ? NSStringFromClass(v) : nil;
                    } break;
                    //选择器类型 :sel
                    case YYEncodingTypeSEL: {
                        SEL v = ((SEL (*)(id, SEL))(void *) objc_msgSend)((id)model, propertyMeta->_getter);
                        value = v ? NSStringFromSelector(v) : nil;
                    } break;
                    default: break;
                }
            }
            if (!value) return;
            
            if (propertyMeta->_mappedToKeyPath) {
                NSMutableDictionary *superDic = dic;
                NSMutableDictionary *subDic = nil;
                for (NSUInteger i = 0, max = propertyMeta->_mappedToKeyPath.count; i < max; i++) {
                    NSString *key = propertyMeta->_mappedToKeyPath[i];
                    if (i + 1 == max) { // end
                        if (!superDic[key]) superDic[key] = value;
                        break;
                    }
                    
                    subDic = superDic[key];
                    if (subDic) {
                        if ([subDic isKindOfClass:[NSDictionary class]]) {
                            subDic = subDic.mutableCopy;
                            superDic[key] = subDic;
                        } else {
                            break;
                        }
                    } else {
                        subDic = [NSMutableDictionary new];
                        superDic[key] = subDic;
                    }
                    superDic = subDic;
                    subDic = nil;
                }
            } else {
                
                //将最终转换的value 和_mappedToKey 存入dic中
                if (!dic[propertyMeta->_mappedToKey]) {
                    dic[propertyMeta->_mappedToKey] = value;
                }
            }
        }];
        
        if (modelMeta->_hasCustomTransformToDictionary) {
            BOOL suc = [((id<YYModel>)model) modelCustomTransformToDictionary:dic];
            if (!suc) return nil;
        }
        return result;
    }
    

    相关文章

      网友评论

          本文标题:YYKit__YYModel_源码分析

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