Runtime机制之结构体及操作函数
一、动态语言
Objective-C语言是一门动态语言,它将很多静态语言在编译和链接时期做的事放到了运行时来处理。这种动态语言的优势在于:具有灵活性,比如:消息转发,方法交换等。它有一个运行时系统Objc Runtime,其实是一个Runtime库,基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。
1. runtime库主要做下面两件事:
- 封装:用c语言把对象封装成基本的数据结构,如:类结构体,对象结构体等。这些结构体和函数被runtime函数封装后,我们就可以在程序运行时创建,检查,修改类、对象和它们的方法了。
- 找出方法的最终执行代码:把消息机制转换为函数的调用。
二、基本结构体
1. 类结构体:objc_class
- isa:指向该类对象所属类(即元类)的指针,根类的元类指向自己
- super_class:指向父类的指针,根类的父类指针指向NULL
- name:类名
- version:版本
- info:类信息
- instance_size:改类实例的大小
- ivars:属性链表
- methodLists:方法链表
- cache:方法缓存链表
- protocols:协议链表
typedef struct objc_class *Class;
struct objc_class { Class isa OBJC_ISA_AVAILABILITY; #if !__OBJC2__ Class super_class OBJC2_UNAVAILABLE; // 父类 const char *name OBJC2_UNAVAILABLE; // 类名 long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0 long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识 long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小 struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表 struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表 struct objc_cache *cache OBJC2_UNAVAILABLE; // 方法缓存 struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表 #endif } OBJC2_UNAVAILABLE;
2. 实例对象结构体:objc_objective
- isa:指向所属类的指针。(仅仅一个指针)
typedef struct objc_object *id; struct objc_object { Class isa OBJC_ISA_AVAILABILITY; };
3. 缓存方法链表结构体:objc_cache
- mask:可缓存方法的数量
- occupied:已缓存方法的数量
- buckets:指针数组,存储的是指针,指向已缓存的方法结构体
typedef struct objc_cache *cache; struct objc_cache { unsigned int mask /* total = mask + 1 */ OBJC2_UNAVAILABLE; unsigned int occupied OBJC2_UNAVAILABLE; Method buckets[1] OBJC2_UNAVAILABLE; };
4. 元类结构体(类对象所属类)
- 同类结构体一样,只是元类的isa指针都是指向根类NSObject元类,而根类的元类的isa指针指向自己。
我们都知道,实例对象拥有一个指向所属类的isa指针。那类本身也可以看成是所属类的对象,即类对象那它自然也拥有一个指向所属类的isa指针,这个指针指向的也是该类对象的所属类,即元类。所以,当我们向一个对象发送消息时,runtime会在这个对象所属的这个类的方法列表中查找方法;而向一个类发送消息时,会在这个类的所属类,即元类meta-class的方法列表中查找。
5. 举例说明,看看以下代码如何执行的
NSArray *array = [[NSArray alloc] init];
- runtime库向类对象NSArray发送了alloc消息,类对象根据isa指针去所属类,即元类中查找响应的方法
- 在元类中,先查cache,再查methodLists,由于元类中没有方法alloc,便根据super_class指针去父类NSObjec中找查找
- 在父类中,同样先查cache,再查methodLists,在methodLists找到,立即响应消息
- 检测类NSArray中instance_size的大小,根据所需的空间大小分配内存
- 创建objc_objective结构体以及实例变量,把结构体的isa指针指向父类
- 把alloc方法缓存到自己的cache链表中
- runtime库又向刚创建好的实例对象发送init消息,对象根据isa指针去所属类NSArray中查找
- 先查cache,再查methodLists,查到后则响应
- 把实例对象中的实例变量初始化
- 把方法init缓存到cache链表中
三、类与对象操作函数
1. 类相关操作函数:以class为前缀命名
- class_getName // 获取类名
- class_getSuperclass // 获取父类
- class_isMetaClass // 判断类是不是元类
- class_getInstanceSize // 获取实例大小
- class_getInstanceVariable // 获取实例成员变量
- class_getClassVariable // 获取类成员变量
- class_addIvar // 添加实例变量
- class_copyIvarList // 获取整个成员变量表
- class_getProperty // 获取指定属性
- class_copyPropertyList // 获取整个属性表
- class_addProperty // 添加属性
- class_replaceProperty // 替换属性
- class_addMethod // 添加方法
- class_getInstanceMethod // 获取实例方法
- class_getClassMethod // 获取类方法
- class_copyMethodList // 获取所有方法的数组
- class_replaceMethod // 替代方法的实现
- class_getMethodImplementation // 返回方法的具体实现
- class_respondsToSelector // 类实例是否响应指定的selector
- class_addProtocol // 添加协议
- class_conformsToProtocol // 返回类是否实现指定的协议
- class_copyProtocolList // 返回类实现的协议列表
- class_getVersion // 获取版本号
- class_setVersion // 设置版本号
-
父类和元类
// 获取类的父类 Class class_getSuperclass ( Class cls ); // 判断给定的Class是否是一个元类 BOOL class_isMetaClass ( Class cls );
-
-
类名
-
// 获取类的类名 const char * class_getName ( Class cls );
-
-
成员变量大小
-
// 获取实例大小 size_t class_getInstanceSize ( Class cls );
-
-
版本
-
// 获取版本号 int class_getVersion ( Class cls ); // 设置版本号 void class_setVersion ( Class cls, int version );
-
-
成员变量
-
/** 成员变量操作函数 */
// 获取类中指定名称实例成员变量的信息 Ivar class_getInstanceVariable ( Class cls, const char *name ); // 获取类成员变量的信息 Ivar class_getClassVariable ( Class cls, const char *name ); // 添加成员变量 BOOL class_addIvar ( Class cls, const char *name, size_t size, uint8_t alignment, const char *types ); // 获取整个成员变量列表 Ivar * class_copyIvarList ( Class cls, unsigned int *outCount );
-
-
属性
-
/** 属性操作函数 */ // 获取指定的属性 objc_property_t class_getProperty ( Class cls, const char *name ); // 获取属性列表 objc_property_t * class_copyPropertyList ( Class cls, unsigned int *outCount ); // 为类添加属性 BOOL class_addProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount ); // 替换类的属性 void class_replaceProperty ( Class cls, const char *name, const objc_property_attribute_t *attributes, unsigned int attributeCount );
-
-
方法
-
// 添加方法 BOOL class_addMethod ( Class cls, SEL name, IMP imp, const char *types ); // 获取实例方法 Method class_getInstanceMethod ( Class cls, SEL name ); // 获取类方法 Method class_getClassMethod ( Class cls, SEL name ); // 获取所有方法的数组 Method * class_copyMethodList ( Class cls, unsigned int *outCount ); // 替代方法的实现 IMP class_replaceMethod ( Class cls, SEL name, IMP imp, const char *types ); // 返回方法的具体实现 IMP class_getMethodImplementation ( Class cls, SEL name ); IMP class_getMethodImplementation_stret ( Class cls, SEL name ); // 类实例是否响应指定的selector BOOL class_respondsToSelector ( Class cls, SEL sel );
-
-
协议
-
// 添加协议 BOOL class_addProtocol ( Class cls, Protocol *protocol ); // 返回类是否实现指定的协议 BOOL class_conformsToProtocol ( Class cls, Protocol *protocol ); // 返回类实现的协议列表 Protocol * class_copyProtocolList ( Class cls, unsigned int *outCount );
2. 对象相关的操作函数,以object为前缀命名
- object_copy // 返回指定对象的一份拷贝
- object_dispose // 释放指定对象占用的内存
- object_setInstanceVariable // 修改类实例的实例变量的值
- object_getInstanceVariable // 获取对象实例变量的值
- object_getIndexedIvars // 返回指向给定对象分配的任何额外字节的指针
- object_getIvar // 返回对象中实例变量的值
- object_setIvar // 设置对象中实例变量的值
- object_getClassName // 返回给定对象的类名
- object_getClass // 返回对象的类
- object_setClass // 设置对象的类
-
-
针对整个对象进行操作的函数
-
// 返回指定对象的一份拷贝 id object_copy ( id obj, size_t size ); // 释放指定对象占用的内存 id object_dispose ( id obj );
-
-
针对对象实例变量进行操作的函数
-
// 修改类实例的实例变量的值 Ivar object_setInstanceVariable ( id obj, const char *name, void *value ); // 获取对象实例变量的值 Ivar object_getInstanceVariable ( id obj, const char *name, void **outValue ); // 返回指向给定对象分配的任何额外字节的指针 void * object_getIndexedIvars ( id obj ); // 返回对象中实例变量的值 id object_getIvar ( id obj, Ivar ivar ); // 设置对象中实例变量的值 void object_setIvar ( id obj, Ivar ivar, id value );
-
-
针对对象的类进行操作的函数
-
// 返回给定对象的类名 const char * object_getClassName ( id obj ); // 返回对象的类 Class object_getClass ( id obj ); // 设置对象的类 Class object_setClass ( id obj, Class cls );
四、动态创建类和对象
1. 动态创建类
- objc_allocateClassPair // 创建一个新类和元类
- objc_disposeClassPair // 销毁一个类及其相关联的类
- objc_registerClassPair // 在应用中注册由objc_allocateClassPair创建的类
// 创建一个新类和元类 Class objc_allocateClassPair ( Class superclass, const char *name, size_t extraBytes ); // 销毁一个类及其相关联的类 void objc_disposeClassPair ( Class cls ); // 在应用中注册由objc_allocateClassPair创建的类 void objc_registerClassPair ( Class cls );
2. 动态创建对象
- class_createInstance // 创建类实例
- objc_constructInstance // 在指定位置创建类实例
- objc_destructInstance // 销毁类实例
// 创建类实例 id class_createInstance ( Class cls, size_t extraBytes ); // 在指定位置创建类实例 id objc_constructInstance ( Class cls, void *bytes ); // 销毁类实例 void * objc_destructInstance ( id obj );
五、获取类定义
1. Objective-C动态运行库会自动注册我们代码中定义的所有的类。我们也可以在运行时创建类定义并使用objc_addClass函数来注册它们。
// 获取已注册的类定义的列表 int objc_getClassList ( Class *buffer, int bufferCount ); // 创建并返回一个指向所有已注册类的指针列表 Class * objc_copyClassList ( unsigned int *outCount ); // 返回指定类的类定义 Class objc_lookUpClass ( const char *name ); Class objc_getClass ( const char *name ); Class objc_getRequiredClass ( const char *name ); // 返回指定类的元类 Class objc_getMetaClass ( const char *name );