您的位置:首页 > 移动开发 > Objective-C

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

2015-11-03 14:43 1146 查看
紧接上篇,出于对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中的函数指针跳转到对应的函数中去执行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: