类型编码
为了帮助运行时系统,编译器将每个方法的返回值和参数编码成一个C字符串,并将这个字符串和OC的方法选择器进行关联。我们可以用编译器指令@encode来获取这个C字符串。当你给一个指定的类型(这个类型可以是基本数据类型,如int,可以是一个指针,一个结构体,类名等,也就是可以作为sizeof()参数的任何类型),@encode会返回一个将这个类型编码后的C字符串。总结为一句话:用一个C字符串来表示一个数据类型
举例:
int main(int argc, const char * argv[]) {
@autoreleasepool {
char *buf1 = @encode(int);
char *buf2 = @encode(float);
char *buf3 = @encode(NSString *);
NSLog(@"%s",buf1);
NSLog(@"%s",buf2);
NSLog(@"%s",buf3);
}
return 0;
}
输出结果如下:
i
f
@
下面这个列表列出了一些类型码及其代表的意义
Code | Meaning |
---|---|
c | A char |
i | An int |
s | A short |
l | A long |
l | is treated as a 32-bit quantity on 64-bit programs. |
q | A long long |
C | An unsigned char |
I | An unsigned int |
S | An unsigned short |
L | An unsigned long |
Q | An unsigned long long |
f | A float |
d | A double |
B | A C++ bool or a C99 _Bool |
v | A void |
* | A character string (char *) |
@ | An object (whether statically typed or typed id) |
# | A class object (Class) |
: | A method selector (SEL) |
[array type] | An array |
{name=type...} | A structure |
(name=type...) | A union |
bnum | A bit field of num bits |
^type | A pointer to type |
? | An unknown type (among other things, this code is used for function pointers) |
注意:
- OC 不支持 long double类型,@encode(long double)将会返回 d ,和double类型的编码一致。
- c 数组,在经过编码后,会在类型前加上数组的个数,如存储12个float类型的指针数组,将会返回 [12^f]
- 类对象会被当作结构体来处理,如@encode(NSObject)将会返回{NSObject=#}
我们可以将列表中的这些值打印出来
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"char --> %s",@encode(char));
NSLog(@"int --> %s",@encode(int));
NSLog(@"short --> %s",@encode(short));
NSLog(@"long --> %s",@encode(long));
NSLog(@"long long --> %s",@encode(long long));
NSLog(@"unsigned char --> %s",@encode(unsigned char));
NSLog(@"unsigned int --> %s",@encode(unsigned int));
NSLog(@"unsigned short --> %s",@encode(unsigned short));
NSLog(@"unsigned long --> %s",@encode(unsigned long long));
NSLog(@"float --> %s",@encode(float));
NSLog(@"bool --> %s",@encode(bool));
NSLog(@"void --> %s",@encode(void));
NSLog(@"char * --> %s",@encode(char *));
NSLog(@"id --> %s",@encode(id));
NSLog(@"Class --> %s",@encode(Class));
NSLog(@"SEL --> %s",@encode(SEL));
int array[] = {1,2,3};
NSLog(@"int[] --> %s",@encode(typeof(array)));
typedef struct person{
char *name;
int age;
}Person;
NSLog(@"struct --> %s",@encode(Person));
typedef union union_type{
char *name;
int a;
}Union;
NSLog(@"union --> %s",@encode(Union));
int a = 2;
int *b = {&a};
NSLog(@"int[] --> %s",@encode(typeof(b)));
}
return 0;
}
打印结果和列表中所列相同,这里不再列出。
应用示例
区分一个数组中NSNumber值的具体数据类型。
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSNumber *num1 = [NSNumber numberWithInt:1];
NSNumber *num2 = [NSNumber numberWithFloat:1.5];
NSNumber *num3 = [NSNumber numberWithDouble:1.6];
NSNumber *num4 = [NSNumber numberWithChar:'A'];
NSArray *arr = @[num1,num2,num3,num4];
for (int i=0; i<arr.count; i++) {
NSNumber *num = arr[i];
if(0 == strcmp([num objCType], @encode(int))){
NSLog(@"num%d是int型数据",i);
}else if(0 == strcmp([num objCType], @encode(float))){
NSLog(@"num%d是float型数据",i);
}else if(0 == strcmp([num objCType], @encode(double))){
NSLog(@"num%d是double型数据",i);
}else if(0 == strcmp([num objCType], @encode(char))){
NSLog(@"num%d是char型数据",i);
}else{
NSLog(@"num%d是其它类型数据",i);
}
}
}
return 0;
}
方法的类型编码
runtime系统预备了一些编码,这些编码在协议中声明方法时会用到。编码列表如下:
Code | Meaning |
---|---|
r | const |
n | in |
N | inout |
o | out |
O | bycopy |
R | byref |
V | oneway |
属性的类型编码
当我们声明属性时,编译器会产生一些与封装的类,类别或协议相关联的一些元数据,我们可以获得这些元数据类型作为一个@encode编译后的C字符串。总结为一句话:就是用一个C字符串来表示属性的一些描述信息
我们可以通过property_getAttributes函数去获得属性的一个属性或者属性的其他属性经过@encode编码之后的C字符串。这个字符串以T开头,后面紧跟@encode编码后的C字符串,然后用‘,’分隔,最后以V紧跟实例变量的返回值结束。在T和V之间,属性的属性用下列字符来描述:
Code | Meaning |
---|---|
R | The property is read-only (readonly). |
C | The property is a copy of the value last assigned (copy). |
& | The property is a reference to the value last assigned (retain). |
N | The property is non-atomic (nonatomic). |
G<name> | The property defines a custom getter selector name. The name follows the G (for example, GcustomGetter,). |
S<name> | The property defines a custom setter selector name. The name follows the S (for example, ScustomSetter:,). |
D | The property is dynamic (@dynamic). |
W | The property is a weak reference (__weak). |
P | The property is eligible for garbage collection. |
t<encoding> | Specifies the type using old-style encoding. |
代码示例
Person.h
@interface Person : NSObject
@property (nonatomic,copy) NSString *name;
@end
main.m
#import <Foundation/Foundation.h>
#import "Person.h"
#import <objc/runtime.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [[Person alloc] init];
unsigned int outCount = 0;
objc_property_t *props = class_copyPropertyList([p class], &outCount);
for (int i=0 ; i<outCount; i++) {
objc_property_t prop = props[i];
NSLog(@"%s",property_getAttributes(prop));
}
}
return 0;
}
输出结果:
T@"NSString",C,N,V_name
输出结果解释:
T@"NSString":表示这个属性的类型是 NSString 型
C:表示属性的引用类型是 copy
N:表示 nonatomic
V_name: 表示属性生成的实例变量是:_name,我们可以用_name来访问属性name的值。