一、动态语言

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[] 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 );

Runtime机制之结构体及操作函数的更多相关文章

  1. c语言,结构体里面的函数

    以linux-3.2内核代码为例,结构体里面的函数的用法: 例,在某驱动文件中,定义了一个平台设备驱动: static struct platform_driver s3c24xx_led_drive ...

  2. enginefuncs_t 结构体中的函数

    就是常见的 g_engfuncs 中的函数.AMXX 里就是 fakemeta 的 EngFunc_** // 这些函数由引擎提供给EXTDLL使用.mp.dll hl.dll ... typedef ...

  3. C语言结构体中的函数指针

      这篇文章简单的叙述一下函数指针在结构体中的应用,为后面的一系列文章打下基础 本文地址:http://www.cnblogs.com/archimedes/p/function-pointer-in ...

  4. [编程] C语言结构体指针作为函数参数

    结构体指针作为函数参数:结构体变量名代表的是整个集合本身,作为函数参数时传递的整个集合,也就是所有成员,而不是像数组一样被编译器转换成一个指针.如果结构体成员较多,尤其是成员为数组时,传送的时间和空间 ...

  5. C++ 利用指针和数组以及指针和结构体实现一个函数返回多个值

    C++ 利用指针和数组实现一个函数返回多个值demo1 #include <iostream> using namespace std; int* test(int,int,int); i ...

  6. go结构体上的函数

    go结构体上的函数 我们可以将一个方法和一个结构体关联: type Saiyan struct { Name string Power int } func (s *Saiyan) Super() { ...

  7. 局部变量、结构体和main函数

    在函数中定义的变量称为自动局部变量.因为每次调用该函数时,它们都自动“创建”,并且它们的只对于函数来说是局部的,局部对象的变量都会默认为空.局部变量的值只能在定义该变量的函数中访问,不能从函数之外访问 ...

  8. c语言里用结构体和指针函数实现面向对象思想

    一.基础研究 观察如下两个程序a.c和b.c: A.c: B.c: 这两个程序都是要实现在屏幕上第10行40列打印一个绿色的字符c: 这两个程序的数据组织方式是一样的,都是使用结构体,而且对共性和个性 ...

  9. DLL 函数中使用结构体指针作函数参数(C# 调用 C++ 的 DLL)

    存在的问题: 问题1:C++ 与 C# 同样定义的结构体在内存布局上有时并不一致: 问题2:C# 中引入了垃圾自动回收机制,其垃圾回收器可能会重新定位指针所指向的结构体变量. 解决方案: 问题1方案: ...

随机推荐

  1. android学习笔记21——消息提示Toast

    消息提示可细分为两种:大量消息提示——当程序有大量图片.信息需要展示时,采用对话框消息提示: 小量消息提示——当程序只有少量信息需要呈现给用户时,采用轻量级的对话框——Toast; Toast ==& ...

  2. SVN 分支及合并的介绍和实践---命令行

    写在前面 一些相关的概念和原理 进行分支开发的最佳实践 合并的分类 在 Eclipse 中进行合并操作 相关资源 写在前面 本文是由演讲整理而来的,介绍了 SVN 分支与合并的概念.流程和一些实际操作 ...

  3. Android Gradle实用技巧——多渠道打包

    友盟有很多不错的功能,例如渠道统计等. 想要做渠道统计,有一个要求就是要在manifest文件中添加各个渠道的配置.只有一两个渠道还好说,但是渠道多了的话,手动修改然后打包简直是噩梦. 幸好现在And ...

  4. POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)+后缀数组模板

    Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7586   Accepted: 3448 Cas ...

  5. Codeforces Round #356 (Div. 2) C. Bear and Prime 100(转)

    C. Bear and Prime 100 time limit per test 1 second memory limit per test 256 megabytes input standar ...

  6. JAVA NIO中selectedKeys返回的键集,对其中的SelectionKey执行操作之后,是否需要在selectedKeys()中对其执行remove 操作

    今天一个东西需要用到java nio的东西.在网上查了一下资料,发现有Apache的Mina,Netty等,感觉JDK中带的NIO有点鸡肋啊.之前看过这部分的内容,但好长一段时间没有用,也就忘得七七八 ...

  7. Java中的注解是如何工作的?--annotation学习一

    自Java5.0版本引入注解之后,它就成为了Java平台中非常重要的一部分.开发过程中,我们也时常在应用代码中会看到诸如@Override,@Deprecated这样的注解.这篇文章中,我将向大家讲述 ...

  8. vim常用命令笔记(转载)

    添加多行注释:   1. 首先按esc进入命令行模式下,按下Ctrl + v,进入列(也叫区块)模式;   2. 在行首使用上下键选择需要注释的多行;   3. 按下键盘(大写)“I”键,进入插入模式 ...

  9. Python标准库09 当前进程信息 (os包)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 我们在Linux的概念与体系,多次提及进程的重要性.Python的os包中有查询和 ...

  10. nbIoT基础概念

    1. 物理信道(L1与L2之间) 上行:PRACH.PUSCH 下行:PBCH.PDCCH.PDSCH 2.逻辑信道(L2与L3之间) CCCH.DCCH.DTCH 3.信令(L3与NAS层之间) D ...