YYClassInfo做为YYModel的核心类,是YYModel解析Json转模型必不可少的部分,其实它主要是利用runTime来获取class内部信息,从而为json转model提供了便利工具。学习YYClassInfo类有助于理解YYModel的工做原理,也有利于增强runTime的基本功。Let's get started.json
YYClassInfo类.h文件和.m文件其实都是能够分为5个部分,(读者能够看下源代码对比下)分别为:缓存
//YYClassInfo.h
/**
Type encoding's type. */ typedef NS_OPTIONS(NSUInteger, YYEncodingType) { YYEncodingTypeMask = 0xFF, ///< mask of type value YYEncodingTypeUnknown = 0, ///< unknown YYEncodingTypeVoid = 1, ///< void YYEncodingTypeBool = 2, ///< bool YYEncodingTypeInt8 = 3, ///< char / BOOL YYEncodingTypeUInt8 = 4, ///< unsigned char YYEncodingTypeInt16 = 5, ///< short YYEncodingTypeUInt16 = 6, ///< unsigned short YYEncodingTypeInt32 = 7, ///< int YYEncodingTypeUInt32 = 8, ///< unsigned int YYEncodingTypeInt64 = 9, ///< long long YYEncodingTypeUInt64 = 10, ///< unsigned long long YYEncodingTypeFloat = 11, ///< float YYEncodingTypeDouble = 12, ///< double YYEncodingTypeLongDouble = 13, ///< long double YYEncodingTypeObject = 14, ///< id YYEncodingTypeClass = 15, ///< Class YYEncodingTypeSEL = 16, ///< SEL YYEncodingTypeBlock = 17, ///< block YYEncodingTypePointer = 18, ///< void* YYEncodingTypeStruct = 19, ///< struct YYEncodingTypeUnion = 20, ///< union YYEncodingTypeCString = 21, ///< char* YYEncodingTypeCArray = 22, ///< char[10] (for example) YYEncodingTypeQualifierMask = 0xFF00, ///< mask of qualifier YYEncodingTypeQualifierConst = 1 << 8, ///< const YYEncodingTypeQualifierIn = 1 << 9, ///< in YYEncodingTypeQualifierInout = 1 << 10, ///< inout YYEncodingTypeQualifierOut = 1 << 11, ///< out YYEncodingTypeQualifierBycopy = 1 << 12, ///< bycopy YYEncodingTypeQualifierByref = 1 << 13, ///< byref YYEncodingTypeQualifierOneway = 1 << 14, ///< oneway YYEncodingTypePropertyMask = 0xFF0000, ///< mask of property YYEncodingTypePropertyReadonly = 1 << 16, ///< readonly YYEncodingTypePropertyCopy = 1 << 17, ///< copy YYEncodingTypePropertyRetain = 1 << 18, ///< retain YYEncodingTypePropertyNonatomic = 1 << 19, ///< nonatomic YYEncodingTypePropertyWeak = 1 << 20, ///< weak YYEncodingTypePropertyCustomGetter = 1 << 21, ///< getter= YYEncodingTypePropertyCustomSetter = 1 << 22, ///< setter= YYEncodingTypePropertyDynamic = 1 << 23, ///< @dynamic }; YYEncodingType YYEncodingGetType(const char *typeEncoding); 复制代码
解析:以上是YYClassInfo.h文件关于YYEncodingType模块的源代码。首先定义了一个移位枚举类型,该类型的枚举值能够按位取或操做实现多种类型的组合。
其中YYEncodingTypexxx记录了属性的类型,YYEncodingTypeQualifier记录了属性的关键字,YYEncodingTypeProperty记录了属性的修饰。其中YYEncodingTypeMask,YYEncodingTypeQualifierMask,YYEncodingTypePropertyMask,能够实现取值操做,好比其中YYEncodingTypeMask去和枚举值取&操做能够获得低8位的值也就是该枚举的值。也就是说多个枚举值取|操做能够实现多个枚举值的组合,如一个变量能够存储三个枚举值(YYEncodingType,YYEncodingTypeQualifier,YYEncodingTypeProperty)的组合。该变量进行和其中YYEncodingTypeMask取&操做能够取得低8位的值也就是YYEncodingType类型的值经过这种方法就实现了三个状态枚举值得组合与获取具体的哪一种枚举值。
YYEncodingType YYEncodingGetType(const char *typeEncoding); 该方法是获取枚举值的方法具体看实现文件安全
YYEncodingType YYEncodingGetType(const char *typeEncoding) {
char *type = (char *)typeEncoding;
//type为空则返回
if (!type) return YYEncodingTypeUnknown;
size_t len = strlen(type);
//type长度为0,则返回
if (len == 0) return YYEncodingTypeUnknown;
/*** 1.获取YYEncodingTypeQualifier类型值 ***/
//用来存储枚举类型的变量
YYEncodingType qualifier = 0;
//循环结束控制变量
bool prefix = true;
//一下代码用来获取YYEncodingTypeQualifier类型的值存储在qualifier变量里
while (prefix) {
switch (*type) {
case 'r': {
qualifier |= YYEncodingTypeQualifierConst;
type++;
} break;
case 'n': {
qualifier |= YYEncodingTypeQualifierIn;
type++;
} break;
case 'N': {
qualifier |= YYEncodingTypeQualifierInout;
type++;
} break;
case 'o': {
qualifier |= YYEncodingTypeQualifierOut;
type++;
} break;
case 'O': {
qualifier |= YYEncodingTypeQualifierBycopy;
type++;
} break;
case 'R': {
qualifier |= YYEncodingTypeQualifierByref;
type++;
} break;
case 'V': {
qualifier |= YYEncodingTypeQualifierOneway;
type++;
} break;
default: { prefix = false; } break;
}
}
/*** 2. 获取YYEncodingType类型值 ***/
len = strlen(type);
//type长度为0则返回未知类型
if (len == 0) return YYEncodingTypeUnknown | qualifier;
//一下代码用来获取YYEncodingType类型的枚举值,存贮在qualifier变量里
switch (*type) {
case 'v': return YYEncodingTypeVoid | qualifier;
case 'B': return YYEncodingTypeBool | qualifier;
case 'c': return YYEncodingTypeInt8 | qualifier;
case 'C': return YYEncodingTypeUInt8 | qualifier;
case 's': return YYEncodingTypeInt16 | qualifier;
case 'S': return YYEncodingTypeUInt16 | qualifier;
case 'i': return YYEncodingTypeInt32 | qualifier;
case 'I': return YYEncodingTypeUInt32 | qualifier;
case 'l': return YYEncodingTypeInt32 | qualifier;
case 'L': return YYEncodingTypeUInt32 | qualifier;
case 'q': return YYEncodingTypeInt64 | qualifier;
case 'Q': return YYEncodingTypeUInt64 | qualifier;
case 'f': return YYEncodingTypeFloat | qualifier;
case 'd': return YYEncodingTypeDouble | qualifier;
case 'D': return YYEncodingTypeLongDouble | qualifier;
case '#': return YYEncodingTypeClass | qualifier;
case ':': return YYEncodingTypeSEL | qualifier;
case '*': return YYEncodingTypeCString | qualifier;
case '^': return YYEncodingTypePointer | qualifier;
case '[': return YYEncodingTypeCArray | qualifier;
case '(': return YYEncodingTypeUnion | qualifier;
case '{': return YYEncodingTypeStruct | qualifier;
case '@': {
if (len == 2 && *(type + 1) == '?')
return YYEncodingTypeBlock | qualifier;
else
return YYEncodingTypeObject | qualifier;
}
default: return YYEncodingTypeUnknown | qualifier;
}
}
复制代码
解析:以上代码已经加了注释。该方法就是用来获取YYEncodingTypeQualifier 和 YYEncodingType枚举值的组合。(接下来用YYEncodingTypeMask,YYEncodingTypeQualifierMask便可获取具体的值)bash
@interface YYClassIvarInfo : NSObject
@property (nonatomic, assign, readonly) Ivar ivar; ///< ivar opaque struct
@property (nonatomic, strong, readonly) NSString *name; ///< Ivar's name @property (nonatomic, assign, readonly) ptrdiff_t offset; ///< Ivar's offset
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< Ivar's type encoding @property (nonatomic, assign, readonly) YYEncodingType type; ///< Ivar's type
/**
Creates and returns an ivar info object.
@param ivar ivar opaque struct
@return A new object, or nil if an error occurs.
*/
- (instancetype)initWithIvar:(Ivar)ivar;
@end
复制代码
解析:该.h文件主要是用几个属性来存储成员变量的几个具体的值。利用- (instancetype)initWithIvar:(Ivar)ivar方法来实现几个属性的赋值操做,这样就获得了该成员变量的具体信息了。接下来看下具体的实现。框架
- (instancetype)initWithIvar:(Ivar)ivar {
//ivar为空则返回nil
if (!ivar) return nil;
self = [super init];
//保存ivar
_ivar = ivar;
//保存ivar的name
const char *name = ivar_getName(ivar);
if (name) {
_name = [NSString stringWithUTF8String:name];
}
//保存ivar的offset
_offset = ivar_getOffset(ivar);
//保存typeEncoding和type
const char *typeEncoding = ivar_getTypeEncoding(ivar);
if (typeEncoding) {
_typeEncoding = [NSString stringWithUTF8String:typeEncoding];
_type = YYEncodingGetType(typeEncoding);
}
return self;
}
复制代码
解析:以上代码已加注释,其中typeEncoding是苹果定义的一种类型编码,该编码记录了属性的类型。其实该编码能够记录全部类型,包括方法的返回值类型,入参等等。函数
@interface YYClassMethodInfo : NSObject
@property (nonatomic, assign, readonly) Method method; ///< method opaque struct
@property (nonatomic, strong, readonly) NSString *name; ///< method name
@property (nonatomic, assign, readonly) SEL sel; ///< method's selector @property (nonatomic, assign, readonly) IMP imp; ///< method's implementation
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< method's parameter and return types @property (nonatomic, strong, readonly) NSString *returnTypeEncoding; ///< return value's type
@property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *argumentTypeEncodings; ///< array of arguments' type /** Creates and returns a method info object. @param method method opaque struct @return A new object, or nil if an error occurs. */ - (instancetype)initWithMethod:(Method)method; @end 复制代码
解析:以上代码其实和ivar的相似,都是用几个属性来记录该属性的具体信息的,利用- (instancetype)initWithMethod:(Method)method方法实现具体的赋值,这样就记录了这个属性的具体信息了。接下来看下具体实现。工具
@implementation YYClassMethodInfo
- (instancetype)initWithMethod:(Method)method {
//method为空则返回nil
if (!method) return nil;
self = [super init];
//保存method
_method = method;
//保存sel
_sel = method_getName(method);
//保存imp(imp实际上是方法的具体实现函数,记录着方法实现函数的地址)
_imp = method_getImplementation(method);
//保存name
const char *name = sel_getName(_sel);
if (name) {
_name = [NSString stringWithUTF8String:name];
}
//保存typeEncoding
const char *typeEncoding = method_getTypeEncoding(method);
if (typeEncoding) {
_typeEncoding = [NSString stringWithUTF8String:typeEncoding];
}
//保存returnType
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;
}
@end
复制代码
解析:以上代码中typeEncoding是记录着方法的全部参数类型,包括返回值的参数类型,和入参的参数类型。returnType来把typeEncoding来保存返回值类型,argumentTypes来保存方法的入参类型。学习
@interface YYClassPropertyInfo : NSObject
@property (nonatomic, assign, readonly) objc_property_t property; ///< property's opaque struct @property (nonatomic, strong, readonly) NSString *name; ///< property's name
@property (nonatomic, assign, readonly) YYEncodingType type; ///< property's type @property (nonatomic, strong, readonly) NSString *typeEncoding; ///< property's encoding value
@property (nonatomic, strong, readonly) NSString *ivarName; ///< property's ivar name @property (nullable, nonatomic, assign, readonly) Class cls; ///< may be nil @property (nullable, nonatomic, strong, readonly) NSArray<NSString *> *protocols; ///< may nil @property (nonatomic, assign, readonly) SEL getter; ///< getter (nonnull) @property (nonatomic, assign, readonly) SEL setter; ///< setter (nonnull) /** Creates and returns a property info object. @param property property opaque struct @return A new object, or nil if an error occurs. */ - (instancetype)initWithProperty:(objc_property_t)property; @end 复制代码
解析:和ivar,method同样都是用几个属性来保存属性信息,利用- (instancetype)initWithProperty:(objc_property_t)property方法来完成几个属性的赋值,来保存property信息。接下来看下具体的实现ui
- (instancetype)initWithProperty:(objc_property_t)property {
//property为空则返回
if (!property) return nil;
self = [super init];
//保存property
_property = property;
//保存name
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
_typeEncoding = [NSString stringWithUTF8String:attrs[i].value];
type = YYEncodingGetType(attrs[i].value);
if ((type & YYEncodingTypeMask) == YYEncodingTypeObject && _typeEncoding.length) {
//保存class类型
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);
}
//保存protocol类型
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;
//保存getter,setter方法
if (_name.length) {
if (!_getter) {
_getter = NSSelectorFromString(_name);
}
if (!_setter) {
_setter = NSSelectorFromString([NSString stringWithFormat:@"set%@%@:", [_name substringToIndex:1].uppercaseString, [_name substringFromIndex:1]]);
}
}
return self;
}
@end
复制代码
解析:以上对属性的基本信息实现了存储this
@interface YYClassInfo : NSObject
@property (nonatomic, assign, readonly) Class cls; ///< class object
@property (nullable, nonatomic, assign, readonly) Class superCls; ///< super class object
@property (nullable, nonatomic, assign, readonly) Class metaCls; ///< class's meta class object @property (nonatomic, readonly) BOOL isMeta; ///< whether this class is meta class @property (nonatomic, strong, readonly) NSString *name; ///< class name @property (nullable, nonatomic, strong, readonly) YYClassInfo *superClassInfo; ///< super class's class info
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassIvarInfo *> *ivarInfos; ///< ivars
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassMethodInfo *> *methodInfos; ///< methods
@property (nullable, nonatomic, strong, readonly) NSDictionary<NSString *, YYClassPropertyInfo *> *propertyInfos; ///< properties
/**
If the class is changed (for example: you add a method to this class with
'class_addMethod()'), you should call this method to refresh the class info cache.
After called this method, `needUpdate` will returns `YES`, and you should call
'classInfoWithClass' or 'classInfoWithClassName' to get the updated class info.
*/
- (void)setNeedUpdate;
/**
If this method returns `YES`, you should stop using this instance and call
`classInfoWithClass` or `classInfoWithClassName` to get the updated class info.
@return Whether this class info need update.
*/
- (BOOL)needUpdate;
/**
Get the class info of a specified Class.
@discussion This method will cache the class info and super-class info
at the first access to the Class. This method is thread-safe.
@param cls A class.
@return A class info, or nil if an error occurs.
*/
+ (nullable instancetype)classInfoWithClass:(Class)cls;
/**
Get the class info of a specified Class.
@discussion This method will cache the class info and super-class info
at the first access to the Class. This method is thread-safe.
@param className A class name.
@return A class info, or nil if an error occurs.
*/
+ (nullable instancetype)classInfoWithClassName:(NSString *)className;
@end
复制代码
解析:以上属性都是class的基本信息,利用classInfoWithClass方法实现赋值来保存class的信息。
其中ivarInfos,methodInfos,propertyInfos三个都是字典里边的元素是YYClassIvarInfo,YYClassMethodInfo,YYClassPropertyInfo类型。也就是YYClassInfo保存了类的名字,父类,元类,还保存了该类的成员变量,属性,方法等信息。
setNeedUpdate方法是设置要更新该类的信息。needUpdate方法是返回是否须要更新该类的信息classInfoWithClassName是根据类名来获取该类的信息。接下来看下实现。
@implementation YYClassInfo {
//用来判断是否须要更新类信息
BOOL _needUpdate;
}
- (instancetype)initWithClass:(Class)cls {
//cls为空则返回nil
if (!cls) return nil;
self = [super init];
//保存cls
_cls = cls;
//保存superCls
_superCls = class_getSuperclass(cls);
//保存是不是元类
_isMeta = class_isMetaClass(cls);
if (!_isMeta) {
//若是不是元类,那就去获取元类
_metaCls = objc_getMetaClass(class_getName(cls));
}
//保存类名
_name = NSStringFromClass(cls);
//去更新类的信息(主要是ivar,method,property)
[self _update];
//保存父类信息
_superClassInfo = [self.class classInfoWithClass:_superCls];
return self;
}
/**
该方法是来更新类的ivar,method,property信息
*/
- (void)_update {
//首先三者赋值空
_ivarInfos = nil;
_methodInfos = nil;
_propertyInfos = nil;
//获取cls
Class cls = self.cls;
/*** 1.保存method信息 ***/
unsigned int methodCount = 0;
//获取methods列表
Method *methods = class_copyMethodList(cls, &methodCount);
if (methods) {
//遍历methods列表
NSMutableDictionary *methodInfos = [NSMutableDictionary new];
_methodInfos = methodInfos;
for (unsigned int i = 0; i < methodCount; i++) {
//获取每一个method的信息
YYClassMethodInfo *info = [[YYClassMethodInfo alloc] initWithMethod:methods[i]];
//用methodInfos去保存该method信息
if (info.name) methodInfos[info.name] = info;
}
//释放methods对象(由于他是c的对象,须要咱们手动释放)
free(methods);
}
/*** 2.保存property信息 ***/
unsigned int propertyCount = 0;
//获取propertys列表
objc_property_t *properties = class_copyPropertyList(cls, &propertyCount);
if (properties) {
NSMutableDictionary *propertyInfos = [NSMutableDictionary new];
_propertyInfos = propertyInfos;
//遍历propertys列表
for (unsigned int i = 0; i < propertyCount; i++) {
//获取每一个property的信息
YYClassPropertyInfo *info = [[YYClassPropertyInfo alloc] initWithProperty:properties[i]];
//用propertyInfos保存每一个property信息
if (info.name) propertyInfos[info.name] = info;
}
//释放prpperties对象(由于他是c的对象,须要咱们手动释放)
free(properties);
}
/*** 3.保存ivar信息 ***/
unsigned int ivarCount = 0;
//获取ivars列表
Ivar *ivars = class_copyIvarList(cls, &ivarCount);
if (ivars) {
NSMutableDictionary *ivarInfos = [NSMutableDictionary new];
_ivarInfos = ivarInfos;
//遍历ivar列表
for (unsigned int i = 0; i < ivarCount; i++) {
//获取每一个ivar信息
YYClassIvarInfo *info = [[YYClassIvarInfo alloc] initWithIvar:ivars[i]];
//用ivarInfos保存每一个ivar信息
if (info.name) ivarInfos[info.name] = info;
}
//释放ivars对象(由于他是c的对象,须要咱们手动释放)
free(ivars);
}
if (!_ivarInfos) _ivarInfos = @{};
if (!_methodInfos) _methodInfos = @{};
if (!_propertyInfos) _propertyInfos = @{};
//由于刚刚更新过ivar,method,property,因此_needUpdate变量赋值NO
_needUpdate = NO;
}
- (void)setNeedUpdate {
//将_needUpdate变量赋值YES,表明接下来要更新ivar,property,method信息
_needUpdate = YES;
}
- (BOOL)needUpdate {
//返回当前是否须要更新ivar,property,method信息
return _needUpdate;
}
//根据Class来保存类信息
+ (instancetype)classInfoWithClass:(Class)cls {
//cls为空则返回nil
if (!cls) return nil;
//单例建立classCache,metaCache字典(是存储类信息的字典)
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);
//在线程安全下,判断当前类是否是元类,若是是元类就取metaCache的缓存。若是不是元类,就取classCache的缓存
YYClassInfo *info = CFDictionaryGetValue(class_isMetaClass(cls) ? metaCache : classCache, (__bridge const void *)(cls));
//若是取得了缓存,那就判断_needUpdate变量,是否须要更新,若是须要更新就去更新
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;
}
//根据ClassName来保存类信息
+ (instancetype)classInfoWithClassName:(NSString *)className {
//根据className来获取class
Class cls = NSClassFromString(className);
//根据class来获取类信息
return [self classInfoWithClass:cls];
}
@end
复制代码
解析:该类实现代码较多点,咱们来逐一分析。
classInfoWithClassName方法和classInfoWithClass方法是入口方法。classInfoWithClassName方法内部在调用classInfoWithClass方法。因此classInfoWithClass方法是核心方法。
这个方法内部有两个缓存字典classCache,metaCache,根据类名当作key去取缓存的类信息,若是取到了缓存类信息,去判断_needUpdate变量若是须要更新就去更新类信息(ivar,property,method信息)全部这里_update更新方法又是一个核心方法,一会咱们再来解析。以后若是没有获得缓存的类信息,那就去建立类信息(这里调用了initWithClass方法,这个方法稍后再去解析),并缓存到对应的缓存字典里。最后返回该类信息对象。
该入口方法里边有方法的嵌套,classInfoWithClass方法里边嵌套了initWithClass方法,initWithClass方法里边嵌套了classInfoWithClass方法,这样就在不停的调用方法classInfoWithClass去获取父类信息并缓存。结束调用的条件是到了根类了如NSObject的父类找不到便可结束循环。
_update方法
该方法内部首先先清空ivarinfos,_methodInfos,_propertyInfos,接下来在去赋值,起到了更新的做用。最后再把_needUpdate变量赋值为NO。该方法内部具体实现都已经加了注释。
initWithClass方法
该方法首先保存类的基本信息,而后再去调用_update方法更新ivar,property,method信息。这样当前类信息就已经有了(并且以后调用者会把当前类信息进行缓存)以后又调用了classInfoWithClass方法来保存父类的信息(也会进行缓存)。
以上就是关于YYModel框架中的YYClassInfo类的源码解析。该类实现了类的基本信息的获取并进行了线程安全的缓存,使得调用起来速度更快更安全。从中咱们队YYModel有了必定了解,同时学习了相关的runTime知识,相关runTime的方法见下篇文章。