对Objective-C的runtime的一些理解
2016-02-27 17:56
197 查看
首先copy某位博主的写的一段关于runtime的介绍:
这算是从技术层介绍了runtime,下面我结合阅读官方文档谈谈自己对runtime的理解:
在OC中,消息表达式会被转化为objc_msgSend函数调用。比如
就将被转化为
这个函数为动态绑定做了所有需要做的事
函数首先找到选择器(selector)提到的方法实现。因为这个函数是通过receiver的类来精确的找到方法的实现,所以不同的类中有相同的方法是对寻找过程没有影响的。
接着函数调用找到的方法实现,并把接受对象(一个指向这个对象数据指针)和参数都传递给那个方法
最终把方法实现传递过来的返回值作为自己的返回值
消息传递的关键在于编译器为每个类和对象构建的结构。每一个类都包括下面两个必须的因素:
一个指向它父类的指针
一个类分派表。这个表将方法选择器与方法在类具体的地址关联起来。eg.setOrigin方法的选择器将被与setOrigin::(方法实现代码)的地址关联起来。
isa指针
当创建一个新对象时,会为它分配一段内存,这个对象的实例变量也会被初始化。在这个对象的变量中第一个就是一个一个纸箱它的类的指针(isa)。通过这个指针一个对象可以访问它的类,并通过它的类来访问该类继承的所有类。
下图是类和对象的结构因素
当消息传递函数(ojc_msgSend)被传送到一个对象时,消息传递函数由对象的isa指针来得到该对象的类并在这个类里的分派表里训中相应的消息选择器。如果找不到相应的选择器,objc_msgSend函数由该类指向其父类的指针得到其父类,并在父类的分派表中寻找是否有相应的选择器,如此继续,直到回溯到NSObject类。一旦找到相应的选择器,objc_msgSend函数通过分派表调用与选择器对应的函数,并执行相应的函数。
这就是在运行时选择方法实现的方式,用面向对象语言来说,这个方法是被动态绑定到消息了。
为了提高消息传递的速度,runtime系统缓存了它使用过的选择器和方法的地址。每一个类都有一个独立的缓存,这个缓存可以包含自己类的方法,也可以包含继承类的方法。在从分派表搜索之前,消息传递函数首先检查接受对象的缓存。
总结一下消息发送之后是怎么来动态查找相对应的方法
runtime是一套比较底层的纯C语言API, 属于1个C语言库, 包含了很多底层的C语言API。 在我们平时编写的OC代码中, 程序运行过程时, 其实最终都是转成了runtime的C语言代码, runtime算是OC的幕后工作者 。
这算是从技术层介绍了runtime,下面我结合阅读官方文档谈谈自己对runtime的理解:
简要介绍
因为OC会尽可能多的把事情从编译时、连接时延迟到运行时来做,所以它还需要一个运行时的系统来执行编译好的代码(因为只执行编译好的代码还没有做完应该做的事,这些事需要在运行时来做),这个运行时的系统,就是OC的runtime。消息
objc_msgSend函数
OC与其他语言不同的的一点就是OC中的函数调用是采用了消息发送的机制,但是直到程序运行之前,消息都没有与任何方法实现绑定起来。只有在真正运行的时候才会根据函数的名字来确定应该调用的函数。在OC中,消息表达式会被转化为objc_msgSend函数调用。比如
[receiver message]
就将被转化为
objc_msgSend(receiver,selector,arg1,arg2,...)
这个函数为动态绑定做了所有需要做的事
函数首先找到选择器(selector)提到的方法实现。因为这个函数是通过receiver的类来精确的找到方法的实现,所以不同的类中有相同的方法是对寻找过程没有影响的。
接着函数调用找到的方法实现,并把接受对象(一个指向这个对象数据指针)和参数都传递给那个方法
最终把方法实现传递过来的返回值作为自己的返回值
消息传递的关键在于编译器为每个类和对象构建的结构。每一个类都包括下面两个必须的因素:
一个指向它父类的指针
一个类分派表。这个表将方法选择器与方法在类具体的地址关联起来。eg.setOrigin方法的选择器将被与setOrigin::(方法实现代码)的地址关联起来。
isa指针
当创建一个新对象时,会为它分配一段内存,这个对象的实例变量也会被初始化。在这个对象的变量中第一个就是一个一个纸箱它的类的指针(isa)。通过这个指针一个对象可以访问它的类,并通过它的类来访问该类继承的所有类。
下图是类和对象的结构因素
当消息传递函数(ojc_msgSend)被传送到一个对象时,消息传递函数由对象的isa指针来得到该对象的类并在这个类里的分派表里训中相应的消息选择器。如果找不到相应的选择器,objc_msgSend函数由该类指向其父类的指针得到其父类,并在父类的分派表中寻找是否有相应的选择器,如此继续,直到回溯到NSObject类。一旦找到相应的选择器,objc_msgSend函数通过分派表调用与选择器对应的函数,并执行相应的函数。
这就是在运行时选择方法实现的方式,用面向对象语言来说,这个方法是被动态绑定到消息了。
为了提高消息传递的速度,runtime系统缓存了它使用过的选择器和方法的地址。每一个类都有一个独立的缓存,这个缓存可以包含自己类的方法,也可以包含继承类的方法。在从分派表搜索之前,消息传递函数首先检查接受对象的缓存。
总结一下消息发送之后是怎么来动态查找相对应的方法
首先,编译器将代码[receiver message];转化为objc_msgSend(receiver, @selector (message));,在objc_msgSend函数中。首先通过obj的isa指针找到obj对应的class。在Class中先去cache中 通过SEL查找对应函数method,若 cache中未找到。再去类的分派表中查找,若分派表中未找到,则取superClass中查找,如此一致回溯至NSObject类。若能找到,则将method加入到cache中,以方便下次查找,并跳转到对应的函数中去执行。
相关文章推荐
- Android Manifest 用法
- 什么是 GraphQL?
- 如何组织构建多文件 C 语言程序(二)
- Spark RDD API详解(一) Map和Reduce
- 如何写好 C main 函数
- lwn拾遗:[sn3218 led drivers]-api解释-1
- 一个小型js框架myJSFrame附API使用帮助
- 详细分析交换机、路由器、集线器的区别和联系
- PowerShell打开或关闭光驱
- 批处理的api WMIC学习体会有感第1/2页
- 批处理 API实现文件下载的代码第1/2页
- Lua和C语言的交互详解
- Lua教程(十七):C API简介
- 强制删除工具 xdelbox xdelbox1.5正式版下载
- 揪出交换机端口背后“凶手”导致网速太慢
- 电脑重启后突然检测不到硬盘的原因分析与解决办法
- C#中设计、使用Fluent API
- Google官方支持的NodeJS访问API,提供后台登录授权
- PQ分区出错! 巧用Ghost急速补救的绝妙办法
- 关于C语言中参数的传值问题