iOS Type Encodings

402 阅读3分钟

先测试下Objective-C的方法通过编译变成了什么?

@interface Person : NSObject
@property (nonatomic, strong) NSString* name;
@property (nonatomic, assign) NSInteger age;

- (void)test;
@end

@implementation Person

- (void)test {
    NSLog(@"%s",__func__);
}

+ (void)test {
    NSLog(@"%s",__func__);
}

@end

通过

    clang -arch x86_64 -rewrite-objc main.m -o main.cpp

获取到cpp 文件,发现里面有

static struct /*_method_list_t*/ {
	unsigned int entsize;  // sizeof(struct _objc_method)
	unsigned int method_count;
	struct _objc_method method_list[1];
} _OBJC_$_CATEGORY_CLASS_METHODS_NSObject_$_YYExtension __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	sizeof(_objc_method),
	1,
	{{(struct objc_selector *)"test", "v16@0:8", (void *)_C_NSObject_YYExtension_test}}
};

其中这个**"v16@0:8"是什么呢?就是SEL Type Encodings**

- (void)test { }
v -> void 返回值是void
16 -> 总共占用字节数
@ -> OC 对象,就是id self
0 -> self offset 是 0
: -> SEL ,就是SEL cmd
8 -> cmd 的 offset 是 8

To assist the runtime system, the compiler encodes the return and argument types for each method in a character string and associates the string with the method selector. The coding scheme it uses is also useful in other contexts and so is made publicly available with the @encode() compiler directive. When given a type specification, @encode() returns a string encoding that type. The type can be a basic type such as an int, a pointer, a tagged structure or union, or a class name—any type, in fact, that can be used as an argument to the C sizeof() operator.

为了帮助运行时系统,编译器将每个方法的返回和参数类型编码为字符串,并将该字符串与方法选择器关联。它使用的编码方案在其他上下文中也很有用,因此可以通过@encode()编译器指令公开使用。给定类型说明后,@ encode()返回编码该类型的字符串。该类型可以是基本类型,例如int,指针,带标签的结构或联合,或类名-实际上可以用作C sizeof()运算符的参数的任何类型。

    char *buf1 = @encode(int **);
    char *buf2 = @encode(struct key);
    char *buf3 = @encode(Rectangle);

    NSLog(@"buf1->%s buf2->%s buf3->%s",buf1, buf2, buf3);
    // buf1->^^i buf2->{key=if} buf3->{Rectangle=#}
CodeMeaning
sA short
lA long
LAn unsigned long
QAn unsigned long long
fA float
dA double
BA C++ bool or a C99_Bool
vA 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
bnumA bit field of num bits
^typeA pointer to type
?An unknown type (among other things, this code is used for function pointers)
    NSString *format = @"\t";
    NSLog(@"@encode(char)%@ %s", format, @encode(char));
    NSLog(@"@encode(int)%@ %s", format, @encode(int));
    NSLog(@"@encode(long)%@ %s", format, @encode(long));
    NSLog(@"@encode(long long)%@ %s", format, @encode(long long));
    NSLog(@"@encode(unsigned char)%@ %s", format, @encode(unsigned char));
    NSLog(@"@encode(unsigned int)%@ %s", format, @encode(unsigned int));
    NSLog(@"@encode(unsigned short)%@ %s", format, @encode(unsigned short));
    NSLog(@"@encode(unsigned long)%@ %s", format, @encode(unsigned long));
    NSLog(@"@encode(unsigned long long)%@ %s", format, @encode(unsigned long long));
    NSLog(@"@encode(float)%@ %s", format, @encode(float));
    NSLog(@"@encode(float *)%@ %s", format, @encode(float *));
    NSLog(@"@encode(double)%@ %s", format, @encode(double));
    NSLog(@"@encode(double *)%@ %s", format, @encode(double *));
    NSLog(@"@encode(BOOL)%@ %s", format, @encode(BOOL));
    NSLog(@"@encode(void)%@ %s", format, @encode(void));
    NSLog(@"@encode(void *)%@ %s", format, @encode(void *));
    NSLog(@"@encode(char *)%@ %s", format, @encode(char *));
    NSLog(@"@encode(NSObject)%@ %s", format, @encode(NSObject));
    NSLog(@"@encode(NSObject *)%@ %s", format, @encode(NSObject *));
    NSLog(@"@encode([NSObject class])%@ %s", format, @encode(typeof([NSObject class])));
    NSLog(@"@encode(SEL)%@ %s", format, @encode(typeof(@selector(viewDidLoad))));
    int intArray[3] = { 0, 0, 0 };
    NSLog(@"@encode(intArray)%@ %s", format, @encode(typeof(intArray)));
    float floatArray[3] = { 0.1f, 0.2f, 0.3f };
    NSLog(@"@encode(floatArray)%@ %s", format, @encode(typeof(floatArray)));
    typedef struct _struct {
        short a;
        long long b;
        unsigned long long c;
        double *d;
    } Struct;
    NSLog(@"@encode(Struct)%@ %s", format, @encode(typeof(Struct)));
    NSLog(@"@encode(NSError)%@ %s", format, @encode(NSError));
    NSLog(@"@encode(NSError ** )%@ %s", format, @encode(typeof(NSError **)));

输出

 @encode(char)	 c
 @encode(int)	 i
 @encode(long)	 q
 @encode(long long)	 q
 @encode(unsigned char)	 C
 @encode(unsigned int)	 I
 @encode(unsigned short)	 S
 @encode(unsigned long)	 Q
 @encode(unsigned long long)	 Q
 @encode(float)	 f
 @encode(float *)	 ^f
 @encode(double)	 d
 @encode(double *)	 ^d
 @encode(BOOL)	 B
 @encode(void)	 v
 @encode(void *)	 ^v
 @encode(char *)	 *
 @encode(NSObject)	 {NSObject=#}
 @encode(NSObject *)	 @
 @encode([NSObject class)	 #
 @encode(SEL)	 :
 @encode(intArray)	 [3i @encode(floatArray)	 [3f @encode(Struct)	 {_struct=sqQ^d} @encode(NSError)	 {NSError=#^vq@@} @encode(NSError ** )	 ^@

Type Encodings