iOS——runtime

打印 上一主题 下一主题

主题 821|帖子 821|积分 2463

什么是runtime

我们都知道,将源代码转换为可实行的程序,通常要经过三个步骤:编译、链接、运行
C 语言 作为一门静态类语言,在编译阶段就已经确定了全部变量的数据类型,同时也确定好了要调用的函数,以及函数的实现。
而 Objective-C 语言 是一门动态语言。在编译阶段并不知道变量的详细数据类型,也不知道所真正调用的哪个函数。只有在运行时间才查抄变量的数据类型,同时在运行时才会根据函数名查找要调用的详细函数。
而实现 Objective-C 语言 运行机会制的一切基础就是 Runtime。
Runtime 实际上是一个库,这个库使我们可以在程序运行时动态的创建对象、查抄对象,修改类和对象的方法。
runtime中的概念剖析

runtime中的消息发送机制在“消息传递与消息转发”博客中详细教学过,因此这里直接贴博客链接,不多赘述:iOS——消息传递和消息转发

Class(类)

在runtime中,类被界说为指向objc_class结构体的指针。结构体数据结构:
  1. /// An opaque type that represents an Objective-C class.
  2. typedef struct objc_class *Class;
  3. struct objc_class {
  4.     Class _Nonnull isa;                                          // objc_class 结构体的实例指针
  5. #if !__OBJC2__
  6.     Class _Nullable super_class;                                 // 指向父类的指针
  7.     const char * _Nonnull name;                                  // 类的名字
  8.     long version;                                                // 类的版本信息,默认为 0
  9.     long info;                                                   // 类的信息,供运行期使用的一些位标识
  10.     long instance_size;                                          // 该类的实例变量大小;
  11.     struct objc_ivar_list * _Nullable ivars;                     // 该类的实例变量列表
  12.     struct objc_method_list * _Nullable * _Nullable methodLists; // 方法定义的列表
  13.     struct objc_cache * _Nonnull cache;                          // 方法缓存
  14.     struct objc_protocol_list * _Nullable protocols;             // 遵守的协议列表
  15. #endif
  16. };
复制代码
objc_class结构体存放的数据称为元数据
objc_class 结构体 的第一个成员变量是 isa 指针,isa 指针 保存的是所属类的结构体的实例的指针,这里保存的就是 objc_class 结构体的实例指针,而实例换个名字就是对象。换句话说,Class(类) 的本质其实就是一个对象,我们称之为类对象。
object(对象)

在“objc/objc.h”中,Object(对象)被界说为 objc_object 结构体,其数据结构如下:
  1. /// Represents an instance of a class.
  2. struct objc_object {
  3.     Class _Nonnull isa;       // objc_object 结构体的实例指针
  4. };
  5. /// A pointer to an instance of a class.
  6. typedef struct objc_object *id;
复制代码
这里的 id 被界说为一个指向 objc_object 结构体 的指针。从中可以看出 objc_object 结构体 只包罗一个 Class 类型的 isa 指针。
换句话说,一个 Object(对象)唯一保存的就是它所属 Class(类) 的地址。当我们对一个对象,进行方法调用时,好比 [receiver selector];,它会通过 objc_object 结构体的 isa 指针 去找对应的 objc_class 结构体,然后在 objc_class 结构体 的 methodLists(方法列表) 中找到我们调用的方法,然后实行。
Meta Class(元类)

Meta Class(元类) 就是一个类对象所属的 类。一个对象所属的类叫做 类对象,而一个类对象所属的类就叫做 元类。
   Runtime 中把类对象所属类型就叫做 Meta Class(元类),用于形貌类对象自己所具有的特性,而在元类的 methodLists 中,保存了类的方法链表,即所谓的「类方法」。并且类对象中的 isa 指针 指向的就是元类。每个类对象有且仅有一个与之相关的元类。
  我们是通过对象的 isa 指针 找到 对应的 Class(类);然后在 Class(类) 的 method list(方法列表) 中找对应的 selector 。
而 类方法的调用过程 和对象方法调用差不多,流程如下:
通过类对象 isa 指针 找到所属的 Meta Class(元类);
在 Meta Class(元类) 的 method list(方法列表) 中找到对应的 selector;
实行对应的 selector。
好比这段代码:
  1. NSString *testString = [NSString stringWithFormat:@"%d,%s",3, "test"];
复制代码
上边的示例中,stringWithFormat: 被发送给了 NSString 类,NSString 类 通过 isa 指针 找到 NSString 元类,然后在该元类的方法列表中找到对应的 stringWithFormat: 方法,然后实行该方法。
实例对象、类、元类之间的关系


方法(method)

objc_class 结构体 的 methodLists(方法列表)中存放的元素就是 方法(Method)。
先看runtime中objc_method结构体的数据结构:
  1. /// An opaque type that represents a method in a class definition.
  2. /// 代表类定义中一个方法的不透明类型
  3. typedef struct objc_method *Method;
  4. struct objc_method {
  5.     SEL _Nonnull method_name;                    // 方法名
  6.     char * _Nullable method_types;               // 方法类型
  7.     IMP _Nonnull method_imp;                     // 方法实现
  8. };
复制代码

  • 起首来看方法名:SEL 是一个指向 objc_selector 结构体 的指针。SEL的意思同样在“消息传递与消息转发”的博客中有讲:iOS——消息传递和消息转发
  • 其次是方法实现:IMP 的实质是一个函数指针,所指向的就是方法的实现。IMP用来找到函数地址,然后实行函数。IMP在“消息传递与消息转发”的博客中有讲:iOS——消息传递和消息转发
  • 方法类型:方法类型 method_types 是个字符串,用来存储方法的参数类型和返回值类型。
因此,Method 就是将 SEL(方法名) 和 IMP(函数指针) 关联起来,当对一个对象发送消息时,会通过给出的 SEL(方法名) 去找到 IMP(函数指针) ,然后实行。
总结

runtime中紧张还是涉及消息传递和消息转发的内容居多,因此想要更深入的相识runtime,可以再去看我的“消息传递和消息转发”这篇博客学习:iOS——消息传递和消息转发

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

嚴華

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表