浅议运行时

来源:互联网 发布:中国象棋棋谱软件 编辑:程序博客网 时间:2024/05/16 14:51

iOS在执行功能时,会尽可能从编译和链接时推迟到运行时。运行时系统扮演的角色就行我们的电脑系统一样,而我们编写的程序就像在Windows系统里的QQ、QQ音乐,运行时提供给我们程序的运行环境和交互。

程序和运行时系统的交互

首先,代码的执行必须要和运行时系统进行交互,要不然运行是系统怎么能够知道你要干什么?

1.通过Objective-C源代码交互
当编译器要编译Objective-C时,将自动创建一些数据结构和函数。在这些数据结构包含类定义和协议类中定义的方法和对象,以及一些其他的信息。运行时系统就会根据源代码的表达式发送消息。
2.通过类NSObject的方法交互
在我们编写的程序中大部分的类都是NSObject类的子类(NSProxy是一个例外),因此也继承了NSObject的许多方法和行为。例如,NSObject 类定义了description方法,用于返回该类内容的字符串,当我们子类要调用它时,我们可以重写它,运行是系统就会对对象进行一定程度的自我检查,给我们提供更多的类的信息,像这样的方法还有很多,像,isKindOfClass:、isMemberOfClass:……
3.通过运行时给我们提供的函数进行交互
运行时系统是一个有公开接口的动态库,由一些数据结构和函数的集合组成,这些函数支持C和OC语言。这些函数用来访问运行时系统成为可能(这种情况在OC程序中不是必须的)。

消息

在程序和运行时交互时,代码是以消息的表达式转换为对objc_msgSend函数的调用。动态调用方法的途径是通过方法的地址,就像调用函数一样调用它。具体作法是:通过利用NSObject类的methodForSelector:方法,获得指向方法实现的指针,并且使用该指针直接调用方法的实现。如下例子展示了怎样使用指针来调用setFilled:方法的实现

void (*setter)(id,SEL,BOOL);    setter = (void (*)(id,SEL,BOOL))[target methodForSelector:@selector(setFilled:)];    for (int i = 0; i < 1000; i++) {        setter(targetList[i],@selector(setFilled:),YES);    }

objc_msgSend函数
在OC中,消息是直到运行的时候才和方法实现绑定的。编译器会将消息表达式:
[receiver message];
转换成一个对消息函数objc_msgSend的调用。该函数有两个主要参数:消息接受者和消息对应的方法名字:
objc_msgsend(receiver,selector);
那么,该消息函数做了那些事情那?如下听我慢慢道来:
1.根据消息接受者的类型,找到对应的方法实现,不同的类对同一方法有不同的实现
2.然后将指向消息接受者对象的指针以及方法中的参数传给找到的方法实现
3.最后,将方法实现的返回值作为该函数的返回值返回
以上几步,有几点需要注意:
one:在找方法实现时,是根据方法表进行找的,方法表:是将方法选标(方法声明)和该类的方法实现的地址关联起来的一个表。
two:当一个对象被创建时,内存被分配,实例变量也同时被初始化。第一个实例变量就是指向该对象的类结构的指针,叫做isa。通过该指针我们就可以访问它对应的类以及相应的父类。
three:当对象收到消息时,消息函数首先会根据该对象的isa指针找到该对象对应的方法表,并从该方法表中找到该消息的对应的方法选标。如果找不到就继续从父类中去找,知道NSObject类。同时为了加快消息的处理过程,运行时系统会将使用过的方法选标和方法实现的地址放入缓存中。每个类都有一个独立的缓存,同时包括继承的方法和在该类中定义的方法,在调用消息函数中它会首先从类的缓存中去找是否有。
消息框架图如下:
这里写图片描述

生活不易,码字更不易,若您认为有帮助,给个赞吧,亲!如有瑕疵,请指正。

0 0
原创粉丝点击