Objective-C Runtime

来源:互联网 发布:xmind mac 使用教程 编辑:程序博客网 时间:2024/04/20 15:11

最近在学Objective-C的多线程,但是网上别人说先花点时间研究Objective-C的runtime机制会更利于理解多线程里面的很多东西。

简介

Runtime(运行时),其实是一个很单纯的一个概念。根据苹果官方文档,Objective-C尽可能地将以前在编译和链接阶段做出地决定推迟到程序运行时(runtime)做出决定。runtime只是指代码执行的这个阶段,就像编译阶段和链接阶段一样。这样是为了动态(Dynamically)的解决事务。我们先思考,何为Dynamic。Objective-C只是具备动态特性,而并不是动态语言或者动态类型语言。下面举例一段代码:
    id obj = self;    if ([obj respondsToSelector:@selector(doSomething)]) {        [obj performSelector:@selector(doSomething) withObject:Nil afterDelay:0];    }    
在编译阶段,对于编译器来说,它只知道obj是一个id指针,并不知道obj能够具体干哪些活。假如我们直接[obj doSomething]; 很明显,编译器认为obj并没有doSomething这个方法,会直接报错。而有runtime system之后,如上地代码就很好地解决了这个问题。runtime system会检查obj能不能接收doSomething这个消息,然后再确定是否进行函数地调用。
那么为什么要将obj给声明为id呢?直接给它确切地某一个类型不是更好?显然,这样有一个好处就是,多态。obj可以是很多不同地类地对象,而我们也不用详细了obj是具体的哪个类,这个类的结构。这样做既降低了耦合又增强了代码的处理能力。

所以,Objective-C不仅有一个编译器,还有一个运行时系统(runtime system)来执行编译后的代码。

runtime的应用

Objective-C在3个层面上与runtime system进行交互:
1. 源代码
2. 在NSObject中定义的方法
3. 直接去调用runtime functions

源代码:

在大多数情况下,runtime system的工作的是自动且不可见的。我们仅在编写代码和编译代码时用到它。当在编译代码时,编译器会生成一些数据结构和函数来实现动态的特性,而这对程序员是透明的。

NSObject 的方法

在我们应用中,大多数的Cocoa的类都继承自NSObject。而一些NSObject的方法可以很简单向runtime system查询一些我们需要的信息。
1. respondsToSelector:
2. isKindOfClass:
3. isMemberOfClass:
4. conformsToProtocol:

Runtime Functions

runtime functions 可以使我们用C语言做到很多编译器在我们编写Objective-C程序时做的事,但是我们平时在写Objective-C代码时,一般都不会用到runtime functions

消息

在Objective-C中,消息(message)和具体的方法的实现是直到运行时才绑定到一起的。编译器对消息做如下处理
1. [receiver message];2. objc_msgSend(receiver, selector);3. objc_msgSend(receiver, selector, arg1,arg2...);

编译器将1.里面的消息转化为2.里面的消息函数的调用,当有参数时,则转化为形如3.的格式。
消息函数(objc_msgSend)来实现动态的绑定
1. 因为相同的方法可以被不同的类实现,所以具体的实现过程是由objc_msgSend(receiver, selector)里面的receiver决定的
2. 然后消息函数调用确定了的具体实现过程,并将参数一并传入
3. 消息函数将具体实现过程的返回值作为自己的返回值返回。
我们确定消息函数的具体实现则依赖于每个类和对象的结构,每个类的结构都包含以下两个部分:
1. 一个指向父类的指针
2. 一个类调度表(dispatch table), 调度表将方法的标识和对应的方法地址给联系起来。
当一个对象创建之后,系统为其分配了内存,初始化了变量。第一个初始化的是一个指向这个对象的类结构的一个指针,我们称为isa指针。isa指针可以使我们可以通过对象找到其对应的类,并通过这个类,访问到所有其继承的类。

当一条消息被发送给一个对象,消息函数(msgSend)也跟着此对象的isa指针访问到了这个对象的类。消息函数遍历这个类的dispatch table。如果没有找到需要的selelctor,那么消息函数会跟着这个类指向父类的指针,进入父类进行同样的工作,直到找到继承树的最顶端。如果一旦消息函数找到了需要的selector。那么这个函数就直接通过dispatch table进行方法的具体实现。
这就是在运行时确定方法的具体实现。

目前我知道的也就这么多了,如果有不正确的地方希望能够指出,才学了半年,也希望多多交流

原创粉丝点击