Objective-C之我对Runtime的理解(二)
2015-11-03 14:43
1146 查看
紧接上篇,出于对people类c++文件的好奇,也使用clang编译了一下得到people.h如下:
在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 ; // 该类的实例变量大小(包括从父类继承下来的实例变量);
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中的函数指针跳转到对应的函数中去执行。
#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中的函数指针跳转到对应的函数中去执行。
相关文章推荐
- github Object-C javascript 消息互通 WebViewJavascriptBridge
- Objective-C学习笔记之NSData、NSDate
- Objective-C 身份证号码校验
- Object-C 多线程中锁的使用
- <iOS>enumerateKeysAndObjectsUsingBlock的用法
- Objective-C 程序设计 第八章
- ios-iPhone Objective-C EXC_BAD_ACCESS问题
- Does GATHER_STATS_JOB gather all objects’ stats every time?
- sqlserver system object type
- ios 关联对象运用 objc_setAssociatedObject
- Objective-C中的@property和@synthesize用法
- JSONObject文档
- NSMutableAttributedStrings - objectAtIndex:effectiveRange:: Out of bounds错误解决
- id、NSObject *、id<NSObject>、instancetype
- Objective-C之@类别小实例
- PO模式(Page Object Model)
- PHP、JAVA、C#、Object-C 通用的DES加密
- iPhone开发中,在XCode下混合编译 C++/Objective-C
- Objective C(OC)面向对象三大特性之:封装
- Objective -C学习笔记 之copy(复制)