Objective-C总Runtime的那点事儿(一)消息机制【转】
RunTime简称运行时。就是系统在运行的时候的一些机制,其中最主要的是消息机制。对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 )。编译完成之后直接顺序执行,无任何二义性。OC的函数调用成为消息发送。属于动态调用过程。在编译的时候并不能决定真正调用哪个函数(事实证明,在编 译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。
那OC是怎么实现动态调用的呢?下面我们来看看OC通过发送消息来达到动态调用的秘密。假如在OC中写了这样的一个代码:
1
|
[obj makeText]; |
其中obj是一个对象,makeText是一个函数名称。对于这样一个简单的调用。在编译时RunTime会将上述代码转化成
1
|
objc_msgSend(obj,@selector(makeText)); |
首先我们来看看obj这个对象,iOS中的obj都继承于NSObject。
1
2
3
|
@interface NSObject <nsobject> { Class isa OBJC_ISA_AVAILABILITY; }</nsobject> |
在NSObjcet中存在一个Class的isa指针。然后我们看看Class:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
typedef struct objc_class *Class; struct objc_class { Class isa; // 指向metaclass Class super_class ; // 指向其父类 const char *name ; // 类名 long version ; // 类的版本信息,初始化默认为0,可以通过runtime函数class_setVersion和class_getVersion进行修改、读取 long info; // 一些标识信息,如CLS_CLASS (0x1L) 表示该类为普通 class ,其中包含对象方法和成员变量;CLS_META (0x2L) 表示该类为 metaclass,其中包含类方法; long instance_size ; // 该类的实例变量大小(包括从父类继承下来的实例变量); struct objc_ivar_list *ivars; // 用于存储每个成员变量的地址 struct objc_method_list **methodLists ; // 与 info 的一些标志位有关,如CLS_CLASS (0x1L),则存储对象方法,如CLS_META (0x2L),则存储类方法; struct objc_cache *cache; // 指向最近使用的方法的指针,用于提升效率; struct objc_protocol_list *protocols; // 存储该类遵守的协议 } |
我们可以看到,对于一个Class类中,存在很多东西,下面我来一一解释一下:
Class isa:指向metaclass,也就是静态的Class。一般一个Obj对象中的isa会指向普通的Class,这个Class中存储普通成员变量和对 象方法(“-”开头的方法),普通Class中的isa指针指向静态Class,静态Class中存储static类型成员变量和类方法(“+”开头的方 法)。
Class super_class:指向父类,如果这个类是根类,则为NULL。
下面一张图片很好的描述了类和对象的继承关系:
注意:所有metaclass中isa指针都指向跟metaclass。而跟metaclass则指向自身。Root metaclass是通过继承Root class产生的。与root class结构体成员一致,也就是前面提到的结构。不同的是Root metaclass的isa指针指向自身。
Class类中其他的成员这里就先不做过多解释了,下面我们来看看:
@selector (makeText):这是一个SEL方法选择器。SEL其主要作用是快速的通过方法名字(makeText)查找到对应方法的函数指针,然后调用其函 数。SEL其本身是一个Int类型的一个地址,地址中存放着方法的名字。对于一个类中。每一个方法对应着一个SEL。所以iOS类中不能存在2个名称相同 的方法,即使参数类型不同,因为SEL是根据方法名字生成的,相同的方法名称只能对应一个SEL。
下面我们就来看看具体消息发送之后是怎么来动态查找对应的方法的。
首先,编译器将代码[obj makeText];转化为objc_msgSend(obj, @selector (makeText));,在objc_msgSend函数中。首先通过obj的isa指针找到obj对应的class。在Class中先去cache中 通过SEL查找对应函数method(猜测cache中method列表是以SEL为key通过hash表来存储的,这样能提高函数查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,则取superClass中查找。若能找到,则将method加 入到cache中,以方便下次查找,并通过method中的函数指针跳转到对应的函数中去执行。
Objective-C总Runtime的那点事儿(一)消息机制【转】的更多相关文章
- Objective-C总Runtime的那点事儿(一)消息机制
最近在找工作,Objective-C中的Runtime是经常被问到的一个问题,几乎是面试大公司必问的一个问题.当然还有一些其他问题也几乎必问,例 如:RunLoop,Block,内存管理等.其他的问题 ...
- [转]runtime 消息机制
原文地址:http://www.jianshu.com/p/f6300eb3ec3d 一.关于runtime 之前在项目中有遇到过用runtime解决改变全局字体的问题,所以再一次感受到了runtim ...
- 刨根问底Objective-C Runtime
http://chun.tips/blog/2014/11/05/bao-gen-wen-di-objective%5Bnil%5Dc-runtime-(2)%5Bnil%5D-object-and- ...
- 刨根问底Objective-C Runtime(4)- 成员变量与属性
http://chun.tips/blog/2014/11/08/bao-gen-wen-di-objective[nil]c-runtime(4)[nil]-cheng-yuan-bian-lian ...
- runtime——消息机制
本文授权转载,作者:Sindri的小巢(简书) 从异常说起 我们都知道,在iOS中存在这么一个通用类类型id,它可以用来表示任何对象的类型 —— 这意味着我们使用id类型的对象调用任何一个方法,编译器 ...
- NSObject头文件解析 / 消息机制 / Runtime解读 (一)
NSObject头文件解析 当我们需要自定义类都会创建一个NSObject子类, 比如: #import <Foundation/Foundation.h> @interface Clas ...
- ios学习路线—Objective-C(Runtime消息机制)
RunTime简称运行时.就是系统在运行的时候的一些机制,其中最主要的是消息机制.对于C语言,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 ).编译完成之后直接顺序执行,无任何 ...
- iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制
你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...
- 快速上手Runtime(一)之消息机制
Runtime简介 Runtime简称运行时.OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制. 对于C语言,函数的调用在编译的时候会决定调用哪个函数. 对于OC的函数,属于动态 ...
随机推荐
- linux内核学习-
我的博客:www.while0.com 1.端口地址的设置主要有统一编址和独立编址. cat /proc/ioports 可以查询linux主机的设备端口. 2.数据传输控制方式有循环查询,中断和D ...
- Android网络框架Volley(体验篇)
Volley是Google I/O 2013推出的网络通信库,在volley推出之前我们一般会选择比较成熟的第三方网络通信库,如: android-async-http retrofit okhttp ...
- Linux学习笔记20——第一个多线程程序
一 什么是线程 线程:是一个进程内部的一个控制序列. 二 使用POSIX的注意点 1 为了使用线程函数库,必须定义宏_REENTRANT,通过定义_REENTRANT来告诉编译器我们需要可重入功能,可 ...
- vijosP1195“非常男女”计划
vijosP1195“非常男女”计划 链接:https://vijos.org/p/1195 [思路] 人数差. 人数差相等的两点之间的区间一定有男女人数相等. 计目前为止到i的1为sum1,0为su ...
- Dr.com5.2 for linux
最近安装了在ubuntu基础上改的elementaryos,很漂亮,学校提供的破linux客户端不能连上,网上常见的也是旧版本. 最后在百度Dr.com贴吧和这个帖子 http://forum.ubu ...
- hdu 4405概率dp
#include <cstdio> #include <cstring> #include <iostream> #include <cmath> #i ...
- HDU 3078 Network LCA
题意:n个点 m个询问,下面一行是n 个点的权值 再下面n-1行是双向的边 然后m个询问:k u v 若k==0,则把u点的权值改为v,否则回答u->v之间最短路经过点的权值中 第k大的值是多 ...
- win7不能在同一窗口打开文件夹,解决办法
1.由于IE浏览器的主页被劫持,总是忽然弹出搜狗的主页,有的时候,忽然弹出IE浏览器(主页是搜狗),然后又自行关闭,我X,我的电脑竟然不受我控制,这可得了,这里我又要骂宁美国度了,made,组装机装了 ...
- 003-python列表
Python 列表(list) 列表是Python中最基本的数据结构.序列中的每个元素都分配一个数字 - 它的位置,或索引,第一个索引是0,第二个索引是1,依此类推. 列表的基本操作: 索引 切片 追 ...
- hdu4348 - To the moon 可持久化线段树 区间修改 离线处理
法一:暴力! 让干什么就干什么,那么久需要可持久化线段树了. 但是空间好紧.怎么破? 不down标记好了! 每个点维护sum和add两个信息,sum是这段真实的和,add是这段整体加了多少,如果这段区 ...