Skip to content

tuntime

MaoTaoTian edited this page Feb 27, 2018 · 17 revisions

目录

  • 什么是runtime?
  • 与runtime交互
  • 消息发送
  • 动态方法解析
  • 消息转发
  • Method Swizzling

什么是runtime?

因为object-c是一门动态语言,所以它将很多静态语言在编译和链接时期做的事放到了运行时来处理,这种特性意味着Objective-C不仅需要一个编译器,还需要一个运行时系统来执行编译的代码。对于Objective-C来说,这个运行时系统就像一个操作系统一样:它让所有的工作可以正常的运行。这个运行时系统即Objc Runtime。Objc Runtime其实是一个Runtime库,它基本上是用C和汇编写的,这个库使得C语言有了面向对象的能力。这种动态语言的优势在于:我们写代码时更具灵活性,如我们可以把消息转发给我们想要的对象,或者随意交换一个方法的实现等。 比如:在一个类中声明一个方法,但是并没有去实现这个方法,然后在程序中调用这个类的方法,编译阶段编译器仅仅是提示没有找到这个方法,并不会报错,只有程序运行到调用这个方法的地方时,程序就会崩溃。

Runtime库主要做下面几件事:
1、**封装:**在这个库中,对象可以用C语言中的结构体表示,而方法可以用C函数来实现,另外再加上了一些额外的特性。这些结构体和函数被runtime函数封装后,我们就可以在程序运行时创建,检查,修改类、对象和它们的方法了。
2、**找出方法的最终执行代码:**当程序执行[object doSomething]时,会向消息接收者(object)发送一条消息(doSomething),runtime会根据消息接收者是否能响应该消息而做出不同的反应。这将在后面详细介绍。

与runtime交互

oc源代码

这个不用我们关心,直接由编译器来完成。如:会把方法的调用,转化成发送消息的形式。

NSObject方法

Cocoa 中大多数类都继承于 NSObject 类,也就自然继承了它的方法。NSObject类中提供了一些方法与runtime进行交互。 如:

  1. class返回对象的类;
  2. isKindOfClass:isMemberOfClass: 则检查对象是否在指定的类继承体系中;
  3. respondsToSelector: 检查对象能否响应指定的消息;
  4. conformsToProtocol: 检查对象是否实现了指定协议类的方法;
  5. methodForSelector: 则返回指定方法实现的地址;

Runtime函数

如:

  • 创建关联对象
    objc_setAssociatedObject(id _Nonnull object, const void * _Nonnull key, id _Nullable value, objc_AssociationPolicy policy)
  • 获取关联对象
    objc_getAssociatedObject(id _Nonnull object, const void * _Nonnull key)

消息发送

一个基本的消息发送:
id objc_msgSend ( id self, SEL op, ... );

其实编译器会根据情况在objc_msgSendobjc_msgSend_stretobjc_msgSendSuper, 或objc_msgSendSuper_stret 四个方法中选择一个来调用。如果消息是传递给超类,那么会调用名字带有 Super 的函数;如果消息返回值是数据结构而不是简单值时,那么会调用名字带有stret的函数。

如:
objc_msgSend(person, @selector(sayHello));
**简单过程如下: ** 第一个参数是要发送消息的实例,也就是 person 对象。 objc_msgSend 会先查询它的 methodLists 方法列表,使用第二个参数 sayHello 逐个和 person 的 methodLists 中的每一个方法信息的 SEL 进行对比,如果找到对应的方法,就调用它所对应的函数,也就是 IMP,然后调用这个函数。

一个类维护一个运行时可接收的消息分发表;分发表中的每个入口是一个方法(Method),其中key是一个特定名称,即选择器(SEL),其对应一个实现(IMP),即指向底层C函数的指针。

每个对象都会有一个它所属的类。这是面向对象的基本概念,但是在OC中,这对所有数据结构有效。任何数据结构,只要在恰当的位置具有一个指针指向一个class,那么,它都可以被认为是一个对象。 在OC中,一个对象所属于哪个类,是由它的isa指针指向的。这个isa指针指向这个对象所属的class。

这个定义表明:任何以一个指向Class的指针作为首个成员的数据结构都可以被认为是一个objc_object. 最重要的特性就是,你可以向OC中的任何对象发送消息 运行原理就是,当你向一个OC对象发送消息时(上文的@“stringValue”),运行时库会根据对象的isa指针找到这个对象所属的类(上文为例,会找到NSCFString类).这个类会包含一个所有实例方法的列表及一个指向superclass的指针以便可以找到父类的实例方法。运行时库会在类的方法列表以及父类(们)的方法列表中寻找符合这个selector(上文为例,这个selector是"writeToFile:atomically:encoding:error")的方法。找到后即运行这个方法。关键点就是类要定义这个你发送给对象的消息。

一个OC的类其实也是一个对象,意思就是你可以向一个类发送消息。Class的数据结构必然也是以isa指针开始的在二进制级别上与objc_object是完全兼容的。然后一个类结构的下一个字段一定是一个指向super class的指针(或者指向nil,对于基类而言)。

为了可以调用类方法,这个类的isa指针必须指向一个包含这些类方法的类结构体。 这样就引出了meta-class的概念:meta-class是一个类对象的类。 简单解释下:        当你向一个对象发送消息时,runtime会在这个对象所属的那个类的方法列表中查找。        当你向一个类发送消息时,runtime会在这个类的meta-class的方法列表中查找。 meta-class之所以重要,是因为它存储着一个类的所有类方法。每个类都会有一个单独的meta-class,因为每个类的类方法基本不可能完全相同。

Clone this wiki locally