IOS -执行时 (消息传递 )
一 函数调用概述
Objective-C不支持多重继承(同Java和Smalltalk),而C++语言支持多重继承。
Objective-C是动态绑定,它的类库比C++要easy操作。
Objective-C在执行时能够同意依据字符串名字来訪问方法和类。还能够动态连接和加入类。 C++ 跟从面向对象编程里的Simula 67(一种早期OO语言)学派,而Objecive-C属于Smalltalk学派。Simula 67学派更安全。由于大部分错误能够在编译时查出。 在C++里,对象的静态类型决定你能否够发送消息给它,而对Objective-C来说。由动态类型来决定。
Objective-C比C++ 更强调类型的动态性,尽管牺牲了一些运行性能。但因为模型清晰,而牺牲的这些性能能够在今天由更先进的编译技术来弥补。
二 消息的产生
在Objective-c中消息一直到执行时才干绑定到相应的函数: [reveiver message]; 编译器在处理时会将上面的表达式处理称以下这样的形式: objc_msgSend(receiver,selector); 假设方法有多个參数的时候会处理成以下这样的形式: objc_msgSend(receiver,selector,arg1,arg2。…….); 如今我们知道了在Objective-c中函数调用都会被编译器进行预处理,调用obj_msgSend函数进行消息的发送。
这里须要弄明确的selector是什么东东?receiver是怎么样来调用指定的函数的,它在背后是如何实现的?以下将逐一解释。
三 类对象中与消息有关的结构 首先看一下与消息传递有关的几个数据结构和数据类型。 1. struct objc_method_list **methodLists 在上一节中知道在类对象objc_class中有一个结构体 struct objc_method_list **methodLists ,它事实上是方法的映射表。
以下是objc_method_list的结构
在objc_method_list中包括一个objc_method结构体 以下是objc_method的结构体
objc_method用来代表一个方法。其包括一个方法 SEL – 表示该方法的名称,一个types – 表示该方法的參数,一个 IMP - 指向该方法的详细实现的函数指针。
对于每一个參数以下将详细说明。
函数映射表的大致情况例如以下图所看到的
2.SEL (An opaque type that represents a method selector)
被定义为 typedef struct objc_selector *SEL 文档中并没有透露objc_selector是什么东西,但提供了@selector指令来生成:
Objective-C在编译的时候,会依据方法的名字,生成 一个用来区分这种方法唯一的ID,这个ID就是 SEL类型的。
(A selector is the name used to select a method to execute for an object, or the unique identifier that replaces the name when the source code is compiled. A selector by itself doesn’t do anything. It simply identifies a method. The only thing that makes the selector method name different from a plain string is that the compiler makes sure that selectors are unique. )仅仅要方法的名字(包含參数序列)同样,那么它们的 ID都是同样的。
就是 说,无论是超类还是子类,无论是有没有超类和子类的关系,仅仅要名字同样那么ID就是一样的。
说的通俗点。SEL就是一个函数标识,该标识是编译器依据其函数声明原型生成的。那假设两个不同的类假设有同样的函数声明的话会生产同样的ID(Objective-c 是不支持在类内函数重载的),那如何进行区分呢?请继续往下看。
3.IMP ( A pointer to the function of a method implementation)
被定义为typedef id (*IMP)(id, SEL, ...)
IMP是一个函数指针,它指向的函数第一个參数实例变量的地址,即接受消息的对象的地址(receiver),第二个參数是SEL要调用的方法、第三个蚕食是函数參数,它是一个不定參数。函数的返回值为id类型。 IMP 是消息终于调用的运行代码,该是方法是真正的实现代码 。我们能够像在C语言里面一样使用这个函数指针。
- (IMP)methodForSelector:(SEL)aSelector 函数的作用是通过SEL生成的ID来查找和定位函数的实现地址。 MyPrint(self,@selector(Print:),@"Hello World”); 调用MyPrint函数指针所指向的函数。參数分别为receiver,SEL和要传递给函数的參数。 通过上面的样例,我们明确了通过函数的第一个參数receiver能够区分不同类的函数声明同样的函数。
四 Objective-c消息传递
通过上面的一层层剖析和前一节有关类对象的解说,可能你大概明确了Objective-c中消息的传递方式了。
首先,编译器依据函数声明生成一个唯一函数ID,每一个实例变量的第一个成员是isa,它指向类对象,在类对象中保存有该类所拥有的方法列表,通过生成的的函数ID能够找到其相应的函数地址,从而调用函数。
假设在当前类对象的函数映射表中没有找到函数的话,就继续搜索其父类中(每一个类对象的super_class 存储了父类的类对象地址),假设到达其根类还是没找到的话,会报执行时错误。 其步骤例如以下图所看到的:
消息的成功传递依赖于两个重要的要素,通过实例中的 isa指针找到实例所属的类对象,然后通过类对象中的消息映射表找到所要调用的函数。 首先通过传递的selector參数找到消息映射表中的函数。然后调用函数,将实例的地址和參数传递给调用的这 个函数。
最后返回返回值。
类类型的存在使objective-c拥有了执行时识别,动态创建,序列化等机制。
3.消息接收者对象(指向消息接收者对象的指针)以及方法中指定的參数传递给方法实现 IMP。 4.最后。将方法实现的返回值作为该函数的返回值返回。 注:编译器会自己主动插入调用消息函数objc_msgSend。我们无须在代码中显示调用该消息函数。 五 消息传递小结 到这里,我们已经大致明确了Objective-c 中消息的传递的整个过程。
事实上假设你熟悉MFC的话,你会发现Objective-c的执行时和MFC的RTTI挺像的。
下图是MFC的执行时机制,CRuntimeClass相当于Objectiv-c的object_clas类对象,在CRuntimeClass中有指向基类函数的指针。与MFC不同的是object_class没有类似与m_pNext_ClassMFC成员。 1.编译器会将消息转换为对消息函数 objc_msgSend的调用,该函数有两个基本的參数:消息接收者 receiver 和消息相应的方法ID,即SEL, 同一时候接收消息不定參数列表。
2.objc_masSend 通过 receiver中的isa找到类对象,从而找到 SEL 相应的方法实现 IMP。注:由于不同的类对同一方法可能会有不同的实现,所以找到的方法实现依赖于消息接收者(receiver)。 以下再做一下具体消息传递过程:
正由于有像CRuntimeClass和object_class这些类类型的存在才使得它们拥有了执行识别。动态创建。序列化等机制。
下一节将对消息传递做进一步的深层次探究。
最近更新影视资讯
- 韵府群玉
- 老年临终关怀护理集锦9篇
- 如何评价剧场版动画《和谐(harmony/ハーモニー)》原作:伊藤计划 ?
- 智人战胜尼人的决定性因素 是神灵崇拜与艺术品 在3万7千年前智人击败了远比自己强
- 沈阳参考消息(2017年1月11日)
- 密集架区密集架书库图书馆负一楼期刊阅览区中外文期刊图书馆一楼图书借阅区(A-H
- 费维光:脾胃病17方
- 土耳其身为伊斯兰国家,为什么允许“风俗产业”合法化?
- 高中教师教学反思
- 三观尽毁!90后公务员出轨50岁女上司,聊天言语暧昧,妻子怒举报
- 22应用心理学考研347 首师360有调剂院校吗?
- 铃木凉美女士,你仍期待同时收获怜爱与尊敬吗?
- 团建别墅 | 确认过眼神,是能疯一起的人!Boss,今年年会我们泡私家温
- 《归来》观后感
- 翻译伦理的重要性和译者荣辱观建设研究
- 高二语文期末考试测试题及答案
- 国医大师名单!在北京看中医该找谁,这下全知道!
- 这些年爱过的同人文(BG)
- 荷兰深陷风俗业?日本都要甘拜下风,为何能稳坐世界顶尖位置!
- 戴安娜25年前私密录像首次解密:自述性生活,全英国都被炸懵逼了
- 原创上官婉儿为什么必须死,她做的这件事太无耻,李隆基忍无可忍
- 「医药速读社」Paxlovid临床失败 礼来斥巨资引进Kv1.3抑制剂
- 她是韩国性感女神,靠出演“三级片”走红,今41岁韵味不减当年!
- 电影市场有望点燃 好莱坞大片排队上映
- 评荐《传染病(Contagion)》