YYModel 源码阅读记录

最近感觉知识匮乏,成长进步进度缓慢,早就听说YYKit屌到不行,遂来试着读一下,第一个先看YYModel

首先看一下 YYClassInfo这个类,里面实现了对class基本信息的封装 (先大概了解,后面细说)

YYClassIvarInfo,YYClassMethodInfo,YYClassPropertyInfo,YYClassInfo

接下来说一下YYModel的使用(通过一个字典返回该类的实例化对象)注:并不是全部的代码,有些跟逻辑无关的东西省略掉了。

+ (instancetype)modelWithDictionary:(NSDictionary *)dictionary {
    Class cls = [self class];
    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:cls];//获取该类的信息
    if (modelMeta->_hasCustomClassFromDictionary) {
        cls = [cls modelCustomClassForDictionary:dictionary] ?: cls;
    }
    
    NSObject *one = [cls new]; // 创建该类的实例对象,并赋值
    if ([one modelSetWithDictionary:dictionary]) return one; 
    return nil;
}

有两个关键点是_YYModelMeta  and  modelSetWithDictionary:

我们一一来看

_YYModelMeta

+ (instancetype)metaWithClass:(Class)cls {
    if (!cls) return nil;
    static CFMutableDictionaryRef cache;//类信息缓存,是CoreFundation里面的字典(不要被这种名字唬住,使用起来是一样的,可能性能会稍微高一点儿)
    static dispatch_once_t onceToken;
    static dispatch_semaphore_t lock;//这个是dispatch里面的信号量,用来限制同时访问该地方的线程数量,通过dispatch_semaphore_create(1)来限制只有一条线程可以访问,类似线程加锁
    dispatch_once(&onceToken, ^{ // 只执行一次。(通过这一系列操作,实现了类似单例的功能,用来缓存不同的类信息)
        // 类信息缓存初始化
        cache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        lock = dispatch_semaphore_create(1);
    });
    dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);// dispatch信号量的具体使用
    _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;
}

我们来看一下[[_YYModelMeta alloc] initWithClass:cls]; 该类的构造方法都做了什么

- (instancetype)initWithClass:(Class)cls {
    YYClassInfo *classInfo = [YYClassInfo classInfoWithClass:cls];//这里是真正的类信息对象
    // 黑名单
    NSSet *blacklist = nil;
    if ([cls respondsToSelector:@selector(modelPropertyBlacklist)]) {
        NSArray *properties = [(id<YYModel>)cls modelPropertyBlacklist];
        if (properties) {
            blacklist = [NSSet setWithArray:properties];
        }
    }
    // 白名单
    NSSet *whitelist = nil;
    if ([cls respondsToSelector:@selector(modelPropertyWhitelist)]) {
        NSArray *properties = [(id<YYModel>)cls modelPropertyWhitelist];
        if (properties) {
            whitelist = [NSSet setWithArray:properties];
        }
    }
    // 如果该model变量里有其他类的对象,例{@"son":[Son class]}
    NSDictionary *genericMapper = nil;
    if ([cls respondsToSelector:@selector(modelContainerPropertyGenericClass)]) {

    }
    // 这个是获取该类所有属性信息(包括父类)
    NSMutableDictionary *allPropertyMetas = [NSMutableDictionary new];
    YYClassInfo *curClassInfo = classInfo;
    while (curClassInfo && curClassInfo.superCls != nil) {
        curClassInfo = curClassInfo.superClassInfo;
    }
    // 这个是用户自定义了映射关系 还有keypath的处理
    if ([cls respondsToSelector:@selector(modelCustomPropertyMapper)]) {}
    return self;
}

上面删减了大部分的代码,因为该方法篇幅太大,而且使用到了一些还没具体讲到的类和方法,目前我们大概了解到

_YYModelMeta该类的实例对象包含了一个 YYClassInfo对象(类信息对象),还有黑白名单的处理,获取所有父类属性,以及对keypath还有用户自定义映射的处理。(若想了解具体实现参阅源码)

接下来讲 YYClassInfo

该类也有个类方法 classInfoWithClass: 具体实现跟_YYModelMeta的相仿,需要注意的是有一个元类信息的缓存- metaCache。(以下是代码,不用细看,跟_YYModelMeta几乎一样)

对于元类不了解的同学可以看下我的这篇文章类探究-isa

+ (instancetype)classInfoWithClass:(Class)cls {
    if (!cls) return nil;
    static CFMutableDictionaryRef classCache;// 类信息缓存
    static CFMutableDictionaryRef metaCache; // 元类信息缓存
    static dispatch_once_t onceToken;
    static dispatch_semaphore_t lock;
    dispatch_once(&onceToken, ^{
        classCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        metaCache = CFDictionaryCreateMutable(CFAllocatorGetDefault(), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
        lock = dispatch_semaphore_create(1);
    });
    dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
    YYClassInfo *info = CFDictionaryGetValue(class_isMetaClass(cls) ? metaCache : classCache, (__bridge const void *)(cls));
    if (info && info->_needUpdate) {
        [info _update];
    }
    dispatch_semaphore_signal(lock);
    if (!info) {
        info = [[YYClassInfo alloc] initWithClass:cls];
        if (info) {
            dispatch_semaphore_wait(lock, DISPATCH_TIME_FOREVER);
            CFDictionarySetValue(info.isMeta ? metaCache : classCache, (__bridge const void *)(cls), (__bridge const void *)(info));
            dispatch_semaphore_signal(lock);
        }
    }
    return info;
}

接下来看看 YYClassInfo的构造方法initWithClass:

- (instancetype)initWithClass:(Class)cls {
    _cls = cls;// 本类
    _superCls = class_getSuperclass(cls); //父类
    _isMeta = class_isMetaClass(cls); // 是否是元类
    if (!_isMeta) {
        _metaCls = objc_getMetaClass(class_getName(cls));// 如果不是元类,获取元类
    }
    _name = NSStringFromClass(cls);
    [self _update]; // 获取该类的method property ivar的信息
    _superClassInfo = [self.class classInfoWithClass:_superCls]; //获取父类的类信息
    return self;
}

- (void)_update {
    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); // 获取ivar信息
    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;
}

通过上面代码大概了解到该类包含了本类和父类的类信息,是否是元类,或者自己的元类,以及该类所有的method,property,ivar信息,这里涉及到三个类YYClassMethodInfoYYClassPropertyInfoYYClassIvarInfo来一一说下

YYClassMethodInfo,

- (instancetype)initWithMethod:(Method)method {
    if (!method) return nil;
    self = [super init];
    _method = method;
    _sel = method_getName(method); // 获取SEL
    _imp = method_getImplementation(method); // 获取方法的实现IMP
    const char *name = sel_getName(_sel); // 获取方法名称
    if (name) {
        _name = [NSString stringWithUTF8String:name];
    }
    const char *typeEncoding = method_getTypeEncoding(method);//返回该方法的编码 例如setCenterPlaceholder: 编码以后返回-> v20@0:8B16
    
    if (typeEncoding) {
        _typeEncoding = [NSString stringWithUTF8String:typeEncoding];
    }
    char *returnType = method_copyReturnType(method);
    if (returnType) { // 获取返回类型
        _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;
}

 

YYClassPropertyInfo

- (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];
    }
    
    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 = NSSelectorFromString(_name);
        }
        if (!_setter) {
            _setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [_name substringToIndex:1].uppercaseString, [_name substringFromIndex:1]]);
        }
    }
    return self;
}

YYClassIvarInfo 

- (instancetype)initWithIvar:(Ivar)ivar {
    if (!ivar) return nil;
    self = [super init];
    _ivar = ivar;
    const char *name = ivar_getName(ivar); //变量名
    if (name) {
        _name = [NSString stringWithUTF8String:name];
    }
    _offset = ivar_getOffset(ivar);
    const char *typeEncoding = ivar_getTypeEncoding(ivar);
    if (typeEncoding) {
        _typeEncoding = [NSString stringWithUTF8String:typeEncoding];
        _type = YYEncodingGetType(typeEncoding);
    }
    return self;
}

 

 

接下来回到了这里     NSObject *one = [cls new];    if ([one modelSetWithDictionary:dictionary]) return one; (创建类实例对象,并赋值Dictionary)
 

modelSetWithDictionary:


- (BOOL)modelSetWithDictionary:(NSDictionary *)dic { // 初始化实例对象后的赋值操作

    _YYModelMeta *modelMeta = [_YYModelMeta metaWithClass:object_getClass(self)]; // 该方法介绍过 获取类信息 ,有缓存机制

    ModelSetContext context = {0}; // 这是一个简单的结构体 包含以下三个变量 方便方法传参的时候使用

    context.modelMeta = (__bridge void *)(modelMeta); //类信息

    context.model = (__bridge void *)(self); //当前实例对象

    context.dictionary = (__bridge void *)(dic); // 赋值的字典

    if (modelMeta->_keyMappedCount >= CFDictionaryGetCount((CFDictionaryRef)dic)) { // 比较json的数据条目多,还是类的属性多,谁少就遍历谁,非常机智。。。

        CFDictionaryApplyFunction((CFDictionaryRef)dic, ModelSetWithDictionaryFunction, &context); //此方法为CFFoundation的字典遍历 参数分别为要遍历的字典, 遍历使用的方法, 传入的参数

        if (modelMeta->_keyPathPropertyMetas) { // 如果有KeyPath 类型

            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 {  // 如果字典的count > 对象的属性.count 那就遍历所有属性 

        CFArrayApplyFunction((CFArrayRef)modelMeta->_allPropertyMetas,

                             CFRangeMake(0, modelMeta->_keyMappedCount),

                             ModelSetWithPropertyMetaArrayFunction,  // 这个方法实现里面 包含了KeyPath 和多对一的处理

                             &context);

    }

    return YES;

}

上面可以看出比较关键赋值方法在这里

// 遍历字典
static void ModelSetWithDictionaryFunction(const void *_key, const void *_value, void *_context) {
    ModelSetContext *context = _context;
    __unsafe_unretained _YYModelMeta *meta = (__bridge _YYModelMeta *)(context->modelMeta);
    __unsafe_unretained _YYModelPropertyMeta *propertyMeta = [meta->_mapper objectForKey:(__bridge id)(_key)];
    __unsafe_unretained id model = (__bridge id)(context->model);
    while (propertyMeta) {
        if (propertyMeta->_setter) {
            ModelSetValueForProperty(model, (__bridge __unsafe_unretained id)_value, propertyMeta);
        }
        propertyMeta = propertyMeta->_next;
    };
}

这里用到一个比较关键的类_YYModelPropertyMeta,它的来由是什么呢

我们在_YYModelMeta的构造方法initWithClass:里省略了一部分内容《获取所有属性》,现在放出来(


    
    // 这个是获取该类所有属性信息(包括父类)
    NSMutableDictionary *allPropertyMetas = [NSMutableDictionary new];
    YYClassInfo *curClassInfo = classInfo;
    while (curClassInfo && curClassInfo.superCls != nil) { //这里是遍历父类 但是忽略了root class (NSObject/NSProxy)
        for (YYClassPropertyInfo *propertyInfo in curClassInfo.propertyInfos.allValues) {
    // ... 夹杂一下判空,和黑白名单的
            _YYModelPropertyMeta *meta = [_YYModelPropertyMeta metaWithClassInfo:classInfo
                                                                    propertyInfo:propertyInfo
                                                                         generic:genericMapper[propertyInfo.name]];
            if (!meta || !meta->_name) continue;
            if (!meta->_getter || !meta->_setter) continue; //是否同时有getter和setter方法
            if (allPropertyMetas[meta->_name]) continue;    
            allPropertyMetas[meta->_name] = meta; // 保存到字典里
        }
        curClassInfo = curClassInfo.superClassInfo;
    }
    // 以上可以知道 allPropertyMetas 里面value存的是_YYModelPropertyMeta 对象 , 那么_YYModelPropertyMeta是什么呢?

+ (instancetype)metaWithClassInfo:(YYClassInfo *)classInfo propertyInfo:(YYClassPropertyInfo *)propertyInfo generic:(Class)generic {
    
    // 这里获取该变量是否对应的是一个对象
    if (!generic && propertyInfo.protocols) {
        for (NSString *protocol in propertyInfo.protocols) {
            Class cls = objc_getClass(protocol.UTF8String);
            if (cls) {
                generic = cls;
                break;
            }
        }
    }
    
    _YYModelPropertyMeta *meta = [self new]; //实例化自己
    meta->_name = propertyInfo.name;
    meta->_type = propertyInfo.type;
    meta->_info = propertyInfo;
    meta->_genericCls = generic;
    
    //以下是判断该属性的类型。_type的由来在YYClassPropertyInfo构造方法里
    if ((meta->_type & YYEncodingTypeMask) == YYEncodingTypeObject) {
        meta->_nsType = YYClassGetNSType(propertyInfo.cls);// 这里判断是否是是以NS开头的类(详情见YYClassGetNSType方法)
    } else {
        meta->_isCNumber = YYEncodingTypeIsCNumber(meta->_type);//这里是判断是否是NSNumber(详见YYEncodingTypeIsCNumber方法)
    }
    // 这里是对结构体类型的赋值语句
    if ((meta->_type & YYEncodingTypeMask) == YYEncodingTypeStruct) {
        /*
         It seems that NSKeyedUnarchiver cannot decode NSValue except these structs:
         */
        static NSSet *types = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            NSMutableSet *set = [NSMutableSet new];
            // 32 bit
            [set addObject:@"{CGSize=ff}"];
            [set addObject:@"{CGPoint=ff}"];
            [set addObject:@"{CGRect={CGPoint=ff}{CGSize=ff}}"];
            [set addObject:@"{CGAffineTransform=ffffff}"];
            [set addObject:@"{UIEdgeInsets=ffff}"];
            [set addObject:@"{UIOffset=ff}"];
            // 64 bit
            [set addObject:@"{CGSize=dd}"];
            [set addObject:@"{CGPoint=dd}"];
            [set addObject:@"{CGRect={CGPoint=dd}{CGSize=dd}}"];
            [set addObject:@"{CGAffineTransform=dddddd}"];
            [set addObject:@"{UIEdgeInsets=dddd}"];
            [set addObject:@"{UIOffset=dd}"];
            types = set;
        });
        if ([types containsObject:propertyInfo.typeEncoding]) {
            meta->_isStructAvailableForKeyedArchiver = YES;
        }
    }
    meta->_cls = propertyInfo.cls;
    
    if (generic) { // 这里是对自定义映射类的处理
        meta->_hasCustomClassFromDictionary = [generic respondsToSelector:@selector(modelCustomClassForDictionary:)];
    } else if (meta->_cls && meta->_nsType == YYEncodingTypeNSUnknown) {
        meta->_hasCustomClassFromDictionary = [meta->_cls respondsToSelector:@selector(modelCustomClassForDictionary:)];
    }
    
    if (propertyInfo.getter) {
        if ([classInfo.cls instancesRespondToSelector:propertyInfo.getter]) {
            meta->_getter = propertyInfo.getter;
        }
    }
    if (propertyInfo.setter) {
        if ([classInfo.cls instancesRespondToSelector:propertyInfo.setter]) {
            meta->_setter = propertyInfo.setter;
        }
    }
    
    if (meta->_getter && meta->_setter) { // 如果同时拥有getter setter方法
        /*
         KVC invalid type:
         long double
         pointer (such as SEL/CoreFoundation object)
         */
        switch (meta->_type & YYEncodingTypeMask) {
            case YYEncodingTypeBool:
            case YYEncodingTypeInt8:
            case YYEncodingTypeUInt8:
            case YYEncodingTypeInt16:
            case YYEncodingTypeUInt16:
            case YYEncodingTypeInt32:
            case YYEncodingTypeUInt32:
            case YYEncodingTypeInt64:
            case YYEncodingTypeUInt64:
            case YYEncodingTypeFloat:
            case YYEncodingTypeDouble:
            case YYEncodingTypeObject:
            case YYEncodingTypeClass:
            case YYEncodingTypeBlock:
            case YYEncodingTypeStruct:
            case YYEncodingTypeUnion: {
                meta->_isKVCCompatible = YES; // 以上类型表示可以用kvc直接复制
            } break;
            default: break;
        }
    }
    
    return meta;
}

了解了_YYModelPropertyMeta以后 赋值方法调用到ModelSetValueForProperty() 里来

这个方法比较繁杂,所有的逻辑都在里面了,感兴趣的同学可以自行查阅源码

下面简单大概写一些运用的赋值方法

1.基本数据类型

static force_inline void ModelSetNumberToProperty(__unsafe_unretained id model,
                                                  __unsafe_unretained NSNumber *num,
                                                  __unsafe_unretained _YYModelPropertyMeta *meta) {
    switch (meta->_type & YYEncodingTypeMask) {
        case YYEncodingTypeBool: {
            ((void (*)(id, SEL, bool))(void *) objc_msgSend)((id)model, meta->_setter, num.boolValue);
        } break;
... 还有好多类型

2 .NS开头的type -> 例如NSString,还要判断json里的类型,然后转化成string类型 赋值给String,可以说是很细致了。

            switch (meta->_nsType) {
                case YYEncodingTypeNSString:
                case YYEncodingTypeNSMutableString: {
                    if ([value isKindOfClass:[NSString class]]) {
                        if (meta->_nsType == YYEncodingTypeNSString) {
                            ((void (*)(id, SEL, id))(void *) objc_msgSend)((id)model, meta->_setter, value);
                        } else {
                            ((void (*)(id, SEL, id))(void *) 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;

总结一下:YYModel有两大核心,第一是类型转换,如何将dict里的数据转换成 model属性的类型 推荐同学们仔细看一下这两个类YYClassPropertyInfo,_YYModelPropertyMeta

第二就是类信息的缓存机制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值