Objective-C之我对Runtime的理解(二)

紧接上篇,出于对people类c++文件的好奇,也使用clang编译了一下得到people.h如下:

#ifndef _REWRITER_typedef_people
#define _REWRITER_typedef_people
typedef struct objc_object people;
typedef struct {} _objc_exc_people;
#endif

extern "C" unsigned long OBJC_IVAR_$_people$_name;
extern "C" unsigned long OBJC_IVAR_$_people$_age;
struct people_IMPL {
	struct NSObject_IMPL NSObject_IVARS;
	int _age;
	NSString *_name;
};
可以看到类都是一个struct结构。类中定义了两个实例变量,还有一个struct结构体。people.m编译后:
static NSString * _I_people_name(people * self, SEL _cmd) { return (*(NSString **)((char *)self + OBJC_IVAR_$_people$_name)); }
static void _I_people_setName_(people * self, SEL _cmd, NSString *name) { (*(NSString **)((char *)self + OBJC_IVAR_$_people$_name)) = name; }

static int _I_people_age(people * self, SEL _cmd) { return (*(int *)((char *)self + OBJC_IVAR_$_people$_age)); }
static void _I_people_setAge_(people * self, SEL _cmd, int age) { (*(int *)((char *)self + OBJC_IVAR_$_people$_age)) = age; }
// @end
这里对people的两个实例变量的调用方法进行了定义。


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;
};
extern "C" __declspec(dllimport) struct objc_cache _objc_empty_cache;
#pragma warning(disable:4273)

extern "C" unsigned long int OBJC_IVAR_$_people$_age __attribute__ ((used, section ("__DATA,__objc_ivar"))) = __OFFSETOFIVAR__(struct people, _age);
extern "C" unsigned long int OBJC_IVAR_$_people$_name __attribute__ ((used, section ("__DATA,__objc_ivar"))) = __OFFSETOFIVAR__(struct people, _name);

static struct /*_ivar_list_t*/ {
	unsigned int entsize;  // sizeof(struct _prop_t)
	unsigned int count;
	struct _ivar_t ivar_list[2];
} _OBJC_$_INSTANCE_VARIABLES_people __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	sizeof(_ivar_t),
	2,
	{{(unsigned long int *)&OBJC_IVAR_$_people$_age, "_age", "i", 2, 4},
	 {(unsigned long int *)&OBJC_IVAR_$_people$_name, "_name", "@\"NSString\"", 3, 8}}
};

static struct /*_method_list_t*/ {
	unsigned int entsize;  // sizeof(struct _objc_method)
	unsigned int method_count;
	struct _objc_method method_list[4];
} _OBJC_$_INSTANCE_METHODS_people __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	sizeof(_objc_method),
	4,
	{{(struct objc_selector *)"name", "@16@0:8", (void *)_I_people_name},
	{(struct objc_selector *)"setName:", "v24@0:8@16", (void *)_I_people_setName_},
	{(struct objc_selector *)"age", "i16@0:8", (void *)_I_people_age},
	{(struct objc_selector *)"setAge:", "v20@0:8i16", (void *)_I_people_setAge_}}
};

static struct /*_prop_list_t*/ {
	unsigned int entsize;  // sizeof(struct _prop_t)
	unsigned int count_of_properties;
	struct _prop_t prop_list[2];
} _OBJC_$_PROP_LIST_people __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	sizeof(_prop_t),
	2,
	{{"name","T@\"NSString\",&,N,V_name"},
	{"age","Ti,N,V_age"}}
};

static struct _class_ro_t _OBJC_METACLASS_RO_$_people __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	1, sizeof(struct _class_t), sizeof(struct _class_t), 
	(unsigned int)0, 
	0, 
	"people",
	0, 
	0, 
	0, 
	0, 
	0, 
};

static struct _class_ro_t _OBJC_CLASS_RO_$_people __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	0, __OFFSETOFIVAR__(struct people, _age), sizeof(struct people_IMPL), 
	(unsigned int)0, 
	0, 
	"people",
	(const struct _method_list_t *)&_OBJC_$_INSTANCE_METHODS_people,
	0, 
	(const struct _ivar_list_t *)&_OBJC_$_INSTANCE_VARIABLES_people,
	0, 
	(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_people,
};

extern "C" __declspec(dllimport) struct _class_t OBJC_METACLASS_$_NSObject;

extern "C" __declspec(dllexport) struct _class_t OBJC_METACLASS_$_people __attribute__ ((used, section ("__DATA,__objc_data"))) = {
	0, // &OBJC_METACLASS_$_NSObject,
	0, // &OBJC_METACLASS_$_NSObject,
	0, // (void *)&_objc_empty_cache,
	0, // unused, was (void *)&_objc_empty_vtable,
	&_OBJC_METACLASS_RO_$_people,
};

extern "C" __declspec(dllimport) struct _class_t OBJC_CLASS_$_NSObject;

extern "C" __declspec(dllexport) struct _class_t OBJC_CLASS_$_people __attribute__ ((used, section ("__DATA,__objc_data"))) = {
	0, // &OBJC_METACLASS_$_people,
	0, // &OBJC_CLASS_$_NSObject,
	0, // (void *)&_objc_empty_cache,
	0, // unused, was (void *)&_objc_empty_vtable,
	&_OBJC_CLASS_RO_$_people,
};
static void OBJC_CLASS_SETUP_$_people(void ) {
	OBJC_METACLASS_$_people.isa = &OBJC_METACLASS_$_NSObject;
	OBJC_METACLASS_$_people.superclass = &OBJC_METACLASS_$_NSObject;
	OBJC_METACLASS_$_people.cache = &_objc_empty_cache;
	OBJC_CLASS_$_people.isa = &OBJC_METACLASS_$_people;
	OBJC_CLASS_$_people.superclass = &OBJC_CLASS_$_NSObject;
	OBJC_CLASS_$_people.cache = &_objc_empty_cache;
}
#pragma section(".objc_inithooks$B", long, read, write)
__declspec(allocate(".objc_inithooks$B")) static void *OBJC_CLASS_SETUP[] = {
	(void *)&OBJC_CLASS_SETUP_$_people,
};
static struct _class_t *L_OBJC_LABEL_CLASS_$ [1] __attribute__((used, section ("__DATA, __objc_classlist,regular,no_dead_strip")))= {
	&OBJC_CLASS_$_people,
};
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

在static void OBJC_CLASS_SETUP_$_people(void)函数中,程序对类的一些变量进行了赋值动作,那么这些变量是什么呢?

类的实例变量和函数又是如何被保存下来的?接下来从NSObject.h源码来看:


  Class isa; // 指向metaclass
  Class super_class ; // 指向其父类
  const char *name ; // 类名
  long version ; // 类的版本信息,初始化默认为0,可以通过runtime函数class_setVersion和class_getVersion进行 
修改、读取
  long info; // 一些标识信息,如CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含对象方法和成员变量;CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法;
  long instance_size ; // 该类的实例变量大小(包括从父类继承下来的实例变量);  
  struct objc_ivar_list *ivars; // 用于存储每个成员变量的地址  
  struct objc_method_list **methodLists ; // 与 info 的一些标志位有关,如CLS_CLASS (0x1L),则存储对象方法,如CLS_META (0x2L),则存储类方法;  struct objc_cache *cache; // 指向最近使用的方法的指针,用于提升效率;  
  struct objc_protocol_list *protocols; // 存储该类遵守的协议
消息发送后,动态查找对应方法的过程(以下为网上找到的):

1)编译器将代码[people setName:str];转化为objc_msgSend(obj, @selector (setName));

2)在objc_msgSend函数中,通过obj的isa指针找到obj对应的class。

3)在Class中先去cache中 通过SEL查找对应函数method(猜测cache中method列表是以SEL为key通过hash表来存储的,这样能提高函数查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,则取superClass中查找。若能找到,则将method加 入到cache中,以方便下次查找,并通过method中的函数指针跳转到对应的函数中去执行。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值