以类MyObject为例来进行分析。

头文件:

@interface MyObject : NSObject

@end

源文件:

@interface MyObject ()
{
    int a;
    char *b;
    NSObject *obj;
}

@property (nonatomic, strong) NSString *name;

@end

@implementation MyObject

+ (void)calClassMethod
{
    NSLog(@"class method");
}

- (void)showDescription:(NSString *)str
{
    NSLog(@"%@%@%d", str, self.name, a);
}

@end

通过 clang -rewrite-objc MyObject.m编译成功后,会生成一个MyObject.cpp文件。

现在就来看下这个cpp文件里面的内容是什么。

1. MyObject的类定义生成一个类似的结构体:

struct MyObject_IMPL {
	struct NSObject_IMPL NSObject_IVARS;
	int a;
	char *b;
	NSObject *obj;
	NSString *_name;
};

struct NSObject_IMPL {
	Class isa;
};

以及与runtime相关的一系列结构体:

struct _prop_t {
	const char *name;
	const char *attributes;
};

struct _protocol_t;

struct _objc_method {
	struct objc_selector * _cmd;
	const char *method_type;
	void  *_imp;
};

struct _protocol_t {
	void * isa;  // NULL
	const char *protocol_name;
	const struct _protocol_list_t * protocol_list; // super protocols
	const struct method_list_t *instance_methods;
	const struct method_list_t *class_methods;
	const struct method_list_t *optionalInstanceMethods;
	const struct method_list_t *optionalClassMethods;
	const struct _prop_list_t * properties;
	const unsigned int size;  // sizeof(struct _protocol_t)
	const unsigned int flags;  // = 0
	const char ** extendedMethodTypes;
};

struct _ivar_t {
	unsigned long int *offset;  // pointer to ivar offset location
	const char *name;
	const char *type;
	unsigned int alignment;
	unsigned int  size;
};

struct _class_ro_t {
	unsigned int flags;
	unsigned int instanceStart;
	unsigned int instanceSize;
	unsigned int reserved;
	const unsigned char *ivarLayout;
	const char *name;
	const struct _method_list_t *baseMethods;
	const struct _objc_protocol_list *baseProtocols;
	const struct _ivar_list_t *ivars;
	const unsigned char *weakIvarLayout;
	const struct _prop_list_t *properties;
};

struct _class_t {
	struct _class_t *isa;
	struct _class_t *superclass;
	void *cache;
	void *vtable;
	struct _class_ro_t *ro;
};

struct _category_t {
	const char *name;
	struct _class_t *cls;
	const struct _method_list_t *instance_methods;
	const struct _method_list_t *class_methods;
	const struct _protocol_list_t *protocols;
	const struct _prop_list_t *properties;
};

通过看结构体的名字可以看出来是什么意思,不做详细解释。

2. 会生成4个static类型的C函数,分别是:

static void _C_MyObject_calClassMethod(Class self, SEL _cmd);
static void _I_MyObject_showDescription_(MyObject * self, SEL _cmd, NSString *str);

//是根据@property自动生成的getter和setter
static NSString * _I_MyObject_name(MyObject * self, SEL _cmd);
static void _I_MyObject_setName_(MyObject * self, SEL _cmd, NSString *name);

函数中C代表的是class method,I代表的是instance method。

3. 会创建4个很重要的结构体对象,在OC中其实就是类对象。

struct _class_ro_t _OBJC_METACLASS_RO_$_MyObject;//简化为:METACLASS_RO_MyObject
struct _class_ro_t _OBJC_CLASS_RO_$_MyObject;//简化为:RO_MyObject
struct _class_t OBJC_METACLASS_$_MyObject;//简化为:METACLASS_MyObject
struct _class_t OBJC_CLASS_$_MyObject;//简化为:MyObject

下面就来看看这4个结构体对象是如何定义及如何组织的,为方便阅读,在这里会省去一些不必要的代码。


(used, section ("__DATA,__objc_data"))
struct _class_t MyObject = {
	0, //_class_t *isa = &METACLASS_MyObject,
	0, //_class_t *superclass = &NSObject,
	0, //void *cache = (void *)&_objc_empty_cache,
	0, //void *vtable = (void *)&_objc_empty_vtable, unused
	&RO_MyObject, //_class_ro_t *ro,
};

(used, section ("__DATA,__objc_data"))
struct _class_t METACLASS_MyObject = {
	0, // &METACLASS_NSObject,
	0, // &METACLASS_NSObject,
	0, // (void *)&_objc_empty_cache,
	0, // (void *)&_objc_empty_vtable,unused
	&METACLASS_RO_MyObject,
};

(used, section ("__DATA,__objc_const"))
static struct _class_ro_t RO_MyObject = {
	0,                                    //flags
	__OFFSETOFIVAR__(struct MyObject, a), //instanceStart
	sizeof(struct MyObject_IMPL),         //instanceSize
	0,                                    //reserved
	0,                                    //ivarLayout
	"MyObject",                           //name
	&_OBJC_$_INSTANCE_METHODS_MyObject,   //baseMethods
	0,                                    //baseProtocols
	&_OBJC_$_INSTANCE_VARIABLES_MyObject, //ivars
	0,                                    //weakIvarLayout
	0,                                    //properties
};

(used, section ("__DATA,__objc_const"))
static struct _class_ro_t METACLASS_RO_MyObject = {
	1,                               //flags
	sizeof(struct _class_t),         //instanceStart
	sizeof(struct _class_t),         //instanceSize
	0,                               //reserved
	0,                               //ivarLayout
	"MyObject",                      //name
	&_OBJC_$_CLASS_METHODS_MyObject, //baseMethods
	0,                               //baseProtocols
	0,                               //ivars
	0,                               //weakIvarLayout
	0,                               //properties
};

4. MyObject类中声明的“成员变量”、“Property”、“方法”的生成及组织方式

在上面的RO_MyObjectMETACLASS_RO_MyObject中出现的_OBJC_$_INSTANCE_METHODS_MyObject_OBJC_$_INSTANCE_VARIABLES_MyObject_OBJC_$_CLASS_METHODS_MyObject又是什么呢?

源码一目了然:

(used, section ("__DATA,__objc_const"))
static struct /*_ivar_list_t*/ {
	unsigned int entsize;
	unsigned int count;
	struct _ivar_t ivar_list[4];
} _OBJC_$_INSTANCE_VARIABLES_MyObject = {
	sizeof(_ivar_t),
	4,
	{ {(unsigned long int *)&OBJC_IVAR_$_MyObject$a, "a", "i", 2, 4},
	 {(unsigned long int *)&OBJC_IVAR_$_MyObject$b, "b", "*", 3, 8},
	 {(unsigned long int *)&OBJC_IVAR_$_MyObject$obj, "obj", "@"NSObject"", 3, 8},
	 {(unsigned long int *)&OBJC_IVAR_$_MyObject$_name, "_name", "@"NSString"", 3, 8} }
};

(used, section ("__DATA,__objc_const"))
static struct /*_method_list_t*/ {
	unsigned int entsize;
	unsigned int method_count;
	struct _objc_method method_list[3];
} _OBJC_$_INSTANCE_METHODS_MyObject = {
	sizeof(_objc_method),
	3,
	{ {(struct objc_selector *)"showDescription:", "v24@0:8@16", (void *)_I_MyObject_showDescription_},
	{(struct objc_selector *)"name", "@16@0:8", (void *)_I_MyObject_name},
	{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_MyObject_setName_} }
};

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

在OC中执行的方法或者调用的变量及property都是从这里面去找的。

5. 生成的其他源码


#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)

(used, section ("__DATA,__objc_ivar"))
unsigned long int OBJC_IVAR_$_MyObject$a = __OFFSETOFIVAR__(struct MyObject, a);
unsigned long int OBJC_IVAR_$_MyObject$b = __OFFSETOFIVAR__(struct MyObject, b);
unsigned long int OBJC_IVAR_$_MyObject$obj = __OFFSETOFIVAR__(struct MyObject, obj);
unsigned long int OBJC_IVAR_$_MyObject$_name = __OFFSETOFIVAR__(struct MyObject, _name);

这个__OFFSETOFIVAR__的宏定义的使用寻找变量地址感觉很新奇,以后开发中可以借鉴。

static void OBJC_CLASS_SETUP_$_MyObject(void ) {
	METACLASS_MyObject.isa = &METACLASS_NSObject;
	METACLASS_MyObject.superclass = &METACLASS_NSObject;
	METACLASS_MyObject.cache = &_objc_empty_cache;
	MyObject.isa = &METACLASS_MyObject;
	MyObject.superclass = &NSObject;
	MyObject.cache = &_objc_empty_cache;
}
static void *OBJC_CLASS_SETUP[] = {
	(void *)&OBJC_CLASS_SETUP_$_MyObject,
};
static struct _class_t *L_OBJC_LABEL_CLASS_$ [1] = {
	&MyObject,
};
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

备注

在OC的源文件里有个属性的声明:@property (nonatomic, strong) NSString *name;

在编译之后的C++代码里面有个:struct _prop_t结构体,这个就是表示属性的一个结构体,可是在C++代码里面并没有体现出来name这个属性的结构体对象。如果把@property (nonatomic, strong) NSString *name;放到头文件就会在C++源码中看到这个name属性的结构体对象。编译之后的源码如下:

//_prop_list_t
(used, section ("__DATA,__objc_const"))
static struct {
	unsigned int entsize;  // sizeof(struct _prop_t)
	unsigned int count_of_properties;
	struct _prop_t prop_list[1];
} _OBJC_$_PROP_LIST_MyObject = {
	sizeof(_prop_t),
	1,
	name
};

static struct _class_ro_t RO_MyObject = {
	0, 
	__OFFSETOFIVAR__(struct MyObject, a), 
	sizeof(struct MyObject_IMPL), 
	(unsigned int)0, 
	0, 
	"MyObject",
	&_OBJC_$_INSTANCE_METHODS_MyObject,
	0, 
	&_OBJC_$_INSTANCE_VARIABLES_MyObject,
	0, 
	&_OBJC_$_PROP_LIST_MyObject,
};

说明

在生成的C++源码中会出现(used, section (“__DATA,__objc_const”))(used, section (“__DATA,__objc_ivar”))(used, section (“__DATA,__objc_const”))类似于这种样式的代码,这个表示用这些标示的变量会被放到程序的数据段,程序启动时runtime会从数据段加载这些信息。

End


以上就是对OC代码通过clang编译为C++代码的一些源码的解析及理解。不过在期间也产生了一些疑问:

  1. 以上4个结构体对象创建出来时都只是一些默认赋值,真正的赋值是在OBJC_CLASS_SETUP_$_MyObject函数里面做的,那么该函数是在什么情况下执行呢?
  2. 上面第4点中的成员变量、property、方法都是在编译的情况下生成的是静态数组,那怎么在runtime下动态的添加成员变量、property、方法呢?
  3. 源代码中生成的都是类对象,如果根据类对象创建一个实例对象时,实例对象结构是怎么样的?
  4. 在app启动时,这些类对象及在编译阶段生成的对象是如何加入到runtime中的?
  5. 在有协议、类别和KVO时源码又是什么样的?
  6. 当调用实例对象和类对象的方法时是怎么样一个查询过程?

后续会一一解决。