编译结果

参考资料:

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

  1. 可见 clang 生成了一个变量 OBJC_IVAR_$_SheslClass$sheslVarNumber 用于存储偏移的地址;

  2. Objetive-C 的变量名和类型在 C++ 中都表现为字符串;

  3. 第一个参数存储类型为 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

  1. 在 Runtime 中,第一个参数类型为 SEL,它底层是通过 C++ 的 objc_selector 这个结构实现的
  2. 第二个参数则是方法的类型,字符串的内容看起来是一串神秘的编码,它叫做方法类型编码;这个编码由一个类型与一个字节数构成。比如上面的 @16@:8
    1. @16 表示这个方法的返回值,是一个 16 个字节的对象;
    2. @0:8 是每个选择器都会有的参数,即 id self & SEL op