1. 变量
要说到变量,得先在这里补充一个知识。每当我们定义一个类的时候,在声明property时,总会带上一些修饰词,比如内存管理,是否原子性等,还需要带上这个变量的数据类型,而这一些的声明都是附带在这个变量的属性里的,我们称为property.Attributes,我们试着去获取一个类里变量的attributes看看里面究竟带有一些什么
- 首先我们声明一个Person类,在里面声明了三个参数,有基础数据类型和系统的NSString类型还有自定义的Dog类型,并且我们声明一个方法获取到属性的attributes并用字典的形式返回
1 2 3 4 5 6 |
interface person : NSObject @property (nonatomic,copy) NSString *name; @property (nonatomic,assign) int age; @property (nonatomic,strong) Dog *dog; - (NSDictionary *)allProperties; @end |
2.在Person的实现中,我们通过runtime来获取到值的属性
1 2 3 4 5 6 |
- (NSDictionary *)allProperties{ NSMutableDictionary *dict = [NSMutableDictionary dictionary]; unsigned int count = 0; objc_property_t *properties = class_copyPropertyList([self class], &count); for (NSUInteger i = 0; i |
3.当我们调用allProperties并且打印出这个返回的字典时 我们会得到如下的内容:
1 2 3 4 5 |
{ age = "Ti,N,V_age"; dog = "T@"Dog",&,N,V_dog"; name = "T@"NSString",C,N,V_name"; } |
大喊一声什么鬼,什么i什么N什么C,这是什么东西,别急别急,我们来看一个东西,要理解这些符号就要先了解苹果定义的Type Encodings也就是类型编码,传送门:苹果官方文档,官方文档2在这个文档中,苹果对每一个变量的类型进行了编码,对方法的类型也进行了编码,于是我们获取到变量的attributes时,就是经过编译器编码后得到的属性。
我们参试着来看懂一个编码的类型
dog = “T@”Dog”,&,N,V_dog”;
首先这个T@”Dog” 就是指这个变量是Dog类型,&代表的是retain的在ARC状态下也就是strong类型,N表示的是是nonatomic的,V_dog表示这个变量的名字是dog,我们再来看一下我们的声明,是不是觉得其实并不是那么难看懂呢?具体需要再深入了解的话请查阅官方文档,这里就不再进行赘述:
1 |
@property (nonatomic,strong) Dog *dog; |
2. YYClassInfo 中的EncodingType
2.1 枚举变量类型
打开YYClassInfo我们发现在文件的开头定义了一个枚举类型,这个枚举类型大致分成了三个部分
1 2 3 4 5 |
typedef NS_OPTIONS(NSUInteger, YYEncodingType) { #1 变量的数据类型 #2 method的attributes #3 变量的attributes }; |
接下来我们看一下在YYModel里的具体实现
1 2 3 |
typedef NS_OPTIONS(NSUInteger, YYEncodingType) { // 低八位的值: 变量的数据类型 YYEncodingTypeMask = 0xFF, /// |
这里有个地方可能不太能一下子理解就是为什么定义了三个Mask,分别是
YYEncodingTypeMask
YYEncodingTypeQualifierMask
YYEncodingTypePropertyMask
在枚举里,我们可以看到YY把这个枚举类型分为三类,二进制中,在第八位的时候,定义为变量的类型,第8~16位的时候定义为方法的attributes,第16~24位定义为属性的attributes类型,这样我们也就很好理解为什么要定义三个Mask了,直接可以通过枚举值&对应的mask找到它对应的部分是哪个值,这样是为了区分不同部分的值,我们尝试一下自己举个例子:
1 2 3 4 5 6 7 8 |
typedef NS_OPTIONS(NSUInteger,iKYEncodingType){ iKYEncodingTypeMask = 0xFF, iKYEncodingType1 = 1, iKYEncodingType2 = 2, iKYEncodingType3 = 3, iKYEncodingTypeQualifireMask = 0xFF00, iKYEncodingTypeQualifire1 = 1 |
然后我们定义一个变量拥有Type1 Qualifire2的属性,然后分别想要取出它们Type和Qualifire的类型
1 2 3 4 5 6 7 8 |
typedef NS_OPTIONS(NSUInteger,iKYEncodingType){ iKYEncodingTypeMask = 0xFF, iKYEncodingType1 = 1, iKYEncodingType2 = 2, iKYEncodingType3 = 3, iKYEncodingTypeQualifireMask = 0xFF00, iKYEncodingTypeQualifire1 = 1 |
1 2 3 4 |
NSLog(@"iKYEncodingType1 %d iKYEncodingTypeQualifire2 %d",(int)iKYEncodingType1,(int)iKYEncodingTypeQualifire2); iKYEncodingType test = (iKYEncodingType1|iKYEncodingTypeQualifire2); NSLog(@"%d",(int) test); NSLog(@"iKYEncodingTypeMask %d, iKYEncodingTypeQualifireMask %d",(int)(test&iKYEncodingTypeMask), (int)(test&iKYEncodingTypeQualifireMask)); |
打印的结果:
1 2 3 |
iKYEncodingType1 1 iKYEncodingTypeQualifire2 512 513 iKYEncodingTypeMask 1, iKYEncodingTypeQualifireMask 512 |
是不是跟我们预期一样呢?YYModel用了不同的Mask来取得不同的type的值
2.2 获取类型的方法
这里比较容易理解直接上代码注释
1 2 3 4 5 |
// 获得Type的 encode 返回枚举的YYEncodingType类型 YYEncodingType YYEncodingGetType(const char *typeEncoding) { // 转换const char 为 char char *type = (char *)typeEncoding; // 如果获取不到type或者type长度 |
最后
在中午休息的时候抽空看了一下源码,希望明天能分享多一些,关于runtime的部分推荐一篇文章看完基本对runtime就了解了