我们来分析YYClassInfo这个类,一开始,作者写了3种编码
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
//1.自定义类型 2.NSObject
YYEncodingTypeObject = 14, ///< id
//Class类型
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)
//取得8~16位的值类型:方法类型
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
//取得16~24位的值类型:属性的附加修饰类型
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
};
这里分别有3个Mask,分别是YYEncodingTypeMask,YYEncodingTypeQualifierMask,YYEncodingTypePropertyMask
这个有什么用呢,我们来看个例子就知道了
typedef NS_OPTIONS(NSUInteger, JJEncodingType) {
JJEncodingTypeMask = 0xFF,
JJEncodingType1 = 1,
JJEncodingType2 = 2,
JJEncodingType3 = 3,
JJEncodingTypeQualifireMask = 0xFF00,
JJEncodingTypeQualifire1 = 1 << 8,
JJEncodingTypeQualifire2 = 1 << 9,
JJEncodingTypeQualifire3 = 1 << 10,
};
NSLog(@"JJEncodingType1 %d JJEncodingTypeQualifire2 %d",(int)JJEncodingType1,(int)JJEncodingTypeQualifire2);
JJEncodingType test = (JJEncodingType1|JJEncodingTypeQualifire2);
NSLog(@"%d",(int) test);
NSLog(@"JJEncodingTypeMask %d, JJEncodingTypeQualifireMask %d",(int)(test&JJEncodingTypeMask), (int)(test&JJEncodingTypeQualifireMask));
打印的结果
JJEncodingType1 1 JJEncodingTypeQualifire2 512
513
JJEncodingTypeMask 1, JJEncodingTypeQualifireMask 512
这就很明显了,如果有个属性分别具有JJEncodingType1和JJEncodingTypeQualifire2 的属性,我们可以通过Mask取出来,
然后是获取类型的方法,
//获取Type的 encode 返回枚举的YYEncodingType类型
YYEncodingType YYEncodingGetType(const char *typeEncoding) {
//转换const char 为char
char *type = (char *)typeEncoding;
//如果获取不到type或者type长度<1 则返回未知类型
if (!type) return YYEncodingTypeUnknown;
size_t len = strlen(type);
if (len == 0) return YYEncodingTypeUnknown;
//用qulifier来确定当前type的encode
YYEncodingType qualifier = 0;
bool prefix = true;
//判断method的类型,如果有就type指针+1,判断下一个字符,如果没有则跳出循环
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;
}
}
//获取变化后的type长度
len = strlen(type);
//再一次判断是否为未知类型
if (len == 0) return YYEncodingTypeUnknown | 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;
}
}
知道了如何进行键值编码,我们继续来看YYClassInfo的组成
分别为YYClassIvarInfo,YYClassMethodInfo,YYClassPropertyInfo
@interface YYClassIvarInfo : NSObject
@property (nonatomic, assign, readonly) Ivar ivar; ///< ivar
@property (nonatomic, strong, readonly) NSString *name; ///< 成员变量名
@property (nonatomic, assign, readonly) ptrdiff_t offset; ///< 变量的偏移地址
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< 变量的编码类型
@property (nonatomic, assign, readonly) YYEncodingType type; ///< 转成YYType类型
//通过一个ivar填充YYClassIvarInfo
- (instancetype)initWithIvar:(Ivar)ivar;
@end
@implementation YYClassIvarInfo
- (instancetype)initWithIvar:(Ivar)ivar {
//判断是否为一个合法的ivar
if (!ivar) return nil;
self = [super init];
_ivar = ivar;
//获取ivar的名称
const char *name = ivar_getName(ivar);
if (name) { //转化const char 属性为NSString
_name = [NSString stringWithUTF8String:name];
}
//取得相对偏移量,这样做可以提高获取效率
_offset = ivar_getOffset(ivar);
const char *typeEncoding = ivar_getTypeEncoding(ivar);
if (typeEncoding) { //获取编码并转为YYType
_typeEncoding = [NSString stringWithUTF8String:typeEncoding];
_type = YYEncodingGetType(typeEncoding);
}
return self;
}
@end
@interface YYClassMethodInfo : NSObject
@property (nonatomic, assign, readonly) Method method; ///< 方法
@property (nonatomic, strong, readonly) NSString *name; ///< �方法名
@property (nonatomic, assign, readonly) SEL sel; ///< sel:方法选择器
@property (nonatomic, assign, readonly) IMP imp; ///< 方法实现
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< 方法的编码
@property (nonatomic, strong, readonly) NSString *returnTypeEncoding; ///< 返回值的类型
@property (nullable, nonatomic, strong, readonly) NSArray *argumentTypeEncodings; ///< 方法参数的编码
//通过一个方法填充YYClassMethodInfo
- (instancetype)initWithMethod:(Method)method;
@end
属性的描述信息
@interface YYClassPropertyInfo : NSObject
@property (nonatomic, assign, readonly) objc_property_t property; ///< property
@property (nonatomic, strong, readonly) NSString *name; ///< 属性名
@property (nonatomic, assign, readonly) YYEncodingType type; ///< 属性类型
@property (nonatomic, strong, readonly) NSString *typeEncoding; ///< 属性编码
@property (nonatomic, strong, readonly) NSString *ivarName; ///< �属性对应的ivar名字
@property (nullable, nonatomic, assign, readonly) Class cls; ///< 属性的class
@property (nullable, nonatomic, strong, readonly) NSArray *protocols; ///< 属性的协议簇
@property (nonatomic, assign, readonly) SEL getter; ///< getter (nonnull)
@property (nonatomic, assign, readonly) SEL setter; ///< setter (nonnull)
//用属性填充YYClassPropertyInfo
- (instancetype)initWithProperty:(objc_property_t)property;
@end
暂时写到这里....发现要去恶补c++,所以等有空再更..