参考资料:
clang
我们都知道 Objective-C 是 C++ 的超集。Objetive-C 的代码在编译阶段,先会 clang
被编译为 C++ 代码,然后在 Runtime 上运行。
利用 clang
在命令行里编译 Objective-C 的命令:
1
2
3
4
5
| # ARC
$ clang -fobjc-arc -framework Foundation main.m -o main
# MRC
$ clang -fno-objc-arc -framework Foundation main.m -o main
|
我们使用下面的示例程序,来查看 clang 的编译结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| #import <Foundation/Foundation.h>
@interface SheslClass : NSObject {
NSNumber *sheslVarNumber;
}
@property (nonatomic, copy) NSString *sheslPropertyString;
+ (void)sheslClassMethod;
- (NSNumber *)getSheslVarNumber;
@end
@implementation SheslClass
+ (void)sheslClassMethod { NSLog(@"Hello World"); }
- (NSNumber *)getSheslVarNumber { return sheslVarNumber; }
@end
int main(int argc, char * argv[]) {
[SheslClass sheslClassMethod];
SheslClass *sheslClass = [[SheslClass alloc] init];
return 0;
}
|
我们可以手动将 Objetive-C 代码编译为 C++ 代码:
1
| $ clang -rewrite-objc main.m
|
OC 类的实例变量
SheslClass
的实例变量,通过 C++ 实例 _OBJC_$_INSTANCE_VARIABLES_SheslClass
实现,它的定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| static struct /*_ivar_list_t*/ {
unsigned int entsize; // sizeof(struct _prop_t)
unsigned int count;
struct _ivar_t ivar_list[2];
} _OBJC_$_INSTANCE_VARIABLES_SheslClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_ivar_t), 2,
{
{
(unsigned long int *)&OBJC_IVAR_$_SheslClass$sheslVarNumber,
"sheslVarNumber", "@\"NSNumber\"", 3, 8
}, {
(unsigned long int *)&OBJC_IVAR_$_SheslClass$_sheslPropertyString,
"_sheslPropertyString", "@\"NSString\"", 3, 8
}
}
};
|
我们分析其中的一个变量 sheslVarNumber
:
可见 clang 生成了一个变量 OBJC_IVAR_$_SheslClass$sheslVarNumber
用于存储偏移的地址;
Objetive-C 的变量名和类型在 C++ 中都表现为字符串;
第一个参数存储类型为 unsigned long int *
是地址的强制类型转换,具体的类型由第三个参数确定;
OC 类的实例方法
SheslClass
的实例方法,通过 C++ 实例 _OBJC_$_INSTANCE_METHODS_SheslClass
实现,它的定义如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[3];
} _OBJC_$_INSTANCE_METHODS_SheslClass __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
3,
{
{
(struct objc_selector *)"getSheslVarNumber",
"@16@0:8",
(void *)_I_SheslClass_getSheslVarNumber
}, {
(struct objc_selector *)"sheslPropertyString",
"@16@0:8",
(void *)_I_SheslClass_sheslPropertyString
}, {
(struct objc_selector *)"setSheslPropertyString:",
"v24@0:8@16",
(void *)_I_SheslClass_setSheslPropertyString_
}
}
};
|
我们分析其中的第一个变量 getSheslVarNumber
:
- 在 Runtime 中,第一个参数类型为
SEL
,它底层是通过 C++ 的 objc_selector
这个结构实现的 - 第二个参数则是方法的类型,字符串的内容看起来是一串神秘的编码,它叫做方法类型编码;这个编码由一个类型与一个字节数构成。比如上面的
@16@:8
:@16
表示这个方法的返回值,是一个 16 个字节的对象;@0
与 :8
是每个选择器都会有的参数,即 id self
& SEL op
。