关于runtime的文章中多次提到了类型编码,下边说说类型编码到底是什么鬼。
相关链接:
类型编码(Type Encoding)
作为对Runtime的补充,编译器将每个方法的返回值和参数类型编码为一个字符串,并将其与方法的selector关联在一起。这种编码方案在其它情况下也是非常有用的,因此我们可以使用@encode编译器指令来获取它。当给定一个类型时,@encode返回这个类型的字符串编码。这些类型可以是诸如int、指针这样的基本类型,也可以是结构体、类等类型。事实上,任何可以作为sizeof()操作参数的类型都可以用于@encode()。
char *buf1 = @encode(int **);
char *buf2 = @encode(struct key);
char *buf3 = @encode(Rectangle);
下表列出了类型代码。注意,当编码一个对象用于归档或分配时,有许多代码时重叠的。然而,在编写编码器时,这里有些代码不能使用。也有些代码可以使用,但不是@encode()所产生的。(关于编码对象的归档和分配的更多信息,可见基础框架引用中NSCode类规范。)
char *buf1 = @encode(int);
char *buf2 = @encode(char);
char *buf3 = @encode(long double);
char *buf4 = @encode(void);
char *buf5 = @encode(Class);
char *buf6 = @encode(id);
char *buf7 = @encode(char *);
char *buf8 = @encode(NSArray *);
输出为:
重要:Objective-C 不支持long double 类型。@encode(long double) 返回d,和double编码一样。
数组类型代码是包含在方括号中,在开括号后,数组类型前指定数组中元素的个数。例如,
float a[] = {1.0, 2.0, 3.0};
NSLog(@"array encoding type: %s", @encode(typeof(a)));
输出: array encoding type: [3f]
结构在括号中指定,在圆括号中结合。最先列出结构标记,然后是等号和序列中列出的结构的范围代码
typedef struct example {
id anObject;
char *aString;
int anInt;
} Example;
结构编码如下:
{example=@*i}
对象被当做结构。例如,传递NSObject类名到@encode() 产生如下编码:
{NSObject=#}
NSObject类声明一个实例变量,isa,作为类型类。
注意:尽管@encode()指令不返回它们,在协议中用来声明方法时,运行时系统使用表6-2中列出的额外编码列表来限定类型。
属性类型Property Type
苹果对每一个变量的类型进行了编码,对方法的类型也进行了编码,于是我们获取到变量的attributes时,就是经过编译器编码后得到的属性。
我们来写个方法打印下看看到底是什么鬼?
+ (NSArray *)properties1{
NSArray *propertiesArray = [NSMutableArray array];
// 1.获得所有的属性
unsigned int outCount = 0;
objc_property_t *properties = class_copyPropertyList(self, &outCount);
for (int i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSLog(@"name:%s---attributes:%s",((propertyStruct)property)->name,((propertyStruct)property)->attributes);
//事实上苹果已经给出了我们获取属性attributes的方法
// property_getAttributes(property);
// property_getName(property);
}
return propertiesArray;
}
objc_property_t *properties
的原型大概就是这个样子:
typedef struct property_t {
const char *name;
const char *attributes;
} *propertyStruct;
所以我们可以用这个方法去获取到属性的名字和描述。打印结果如下:
2016-09-01 17:38:29.726 RuntimeDemo[45809:23195325] name:name---attributes:T@"NSString",C,N,V_name
2016-09-01 17:38:29.726 RuntimeDemo[45809:23195325] name:age---attributes:Ti,N,V_age
2016-09-01 17:38:29.726 RuntimeDemo[45809:23195325] name:father---attributes:T@"NSString",C,N,V_father
2016-09-01 17:38:29.727 RuntimeDemo[45809:23195325] name:secondModel---attributes:T@"DDSecondModel",&,N,V_secondModel
2016-09-01 17:38:29.727 RuntimeDemo[45809:23195325] name:thirdModel---attributes:T@"NSArray",&,N,V_thirdModel
NSLog打印的结果可能有点不一样,其实原型是这样的:
"T@\"NSArray\",&,N,V_thirdModel"
中间会多一个@\,这牵扯到c与oc的转换,在OC字符串中 \” -> “,\是转义的意思,不占用字符
我们试着来看懂一个编码的类型,首先这个T@”NSArray”指的这个变量是NSArray类型,&代表的是retain的在ARC状态下也就是strong类型,N表示的是是nonatomic的,V_thirdModel代表这个变量名是thirdModel,再来看看我们的声明,好像是并不是那么难懂,再来查一查官方文档,对这些字符进行了定义:
官方文档又给出了一些例子:
enum FooManChu { FOO, MAN, CHU };
struct YorkshireTeaStruct { int pot; char lady; };
typedef struct YorkshireTeaStruct YorkshireTeaStructType;
union MoneyUnion { float alone; double down; };
文章开头给出了官方文档地址,可以再去看看。