IOS运行时(消息传递)
来源:互联网 发布:聚创淘宝培训 编辑:程序博客网 时间:2024/04/29 11:53
Tag标签:消息
- 一 函数调用概述
1.
Objective-C不支持多重继承(同Java和Smalltalk),而C++语言支持多重继承。 Objective-C是动态绑定,它的类库比C++要容易操作。Objective-C 在运行时可以允许根据字符串名字来访问方法和类,还可以动态连接和添加类。 C++ 跟从面向对象编程里的Simula
67
(一种早期OO语言)学派,而Objecive-C属于Smalltalk学派,Simula
67
学派更安全,因为大部分错误可以在编译时查出。 在C++里,对象的静态类型决定你是否可以发送消息给它,而对Objective-C来说,由动态类型来决定。
1.
Objective-C 比 C++ 更强调类型的动态性,而牺牲了一些执行性能。不过这些牺牲,由于模型清晰,可以在今天,由更先进的编译技术来弥补了。
二消息的产生1.
在Objective-c中消息一直到运行时才能绑定到对应的函数:
1.
[reveiver message];
1.
编译器在处理时会将上面的表达式处理称下面这种形式:
1.
objc_msgSend(receiver,selector);
1.
如果方法有多个参数的时候会处理成下面这种形式:
1.
objc_msgSend(receiver,selector,arg1,arg2,…….);
1.
现在我们知道了在Objective-c中函数调用都会被编译器进行预处理,调用obj_msgSend函数进行消息的发送。这里需要弄明白的selector是什么东东?receiver是怎么样来调用指定的函数的,它在背后是怎样实现的?下面将逐一解释。
1.
三 类对象中与消息有关的结构
1.
首先看一下与消息传递有关的几个数据结构和数据类型。
1.
1
.struct objc_method_list **methodLists
下面是objc_method_list的结构 struct objc_method_list {1.
在上一节中知道在类对象objc_class中有一个结构体 struct objc_method_list **methodLists ,它其实是方法的映射表。
1.
struct objc_method_list *obsolete
2.
int
method_count
3.
struct objc_method method_list[
1
]
1.
}
下面是objc_method的结构体 struct objc_method { SEL method_name char *method_types IMP method_imp }1.
在objc_method_list中包含一个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指令来生成:
SEL method = @selector(viewDidLoad);
NSLog(@"%s",(char *)method);//viewDidLoad
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语言里面一样使用这个函数指针。
- (void) viewDidLoad
{
[super viewDidLoad]; //声明一个函数指针
void (*MyPrint)(id,SEL,NSString*);
MyPrint = ( void (*)(id,SEL,NSString*) )[self methodForSelector:@selector(Print:)];
MyPrint(self,@selector(Print:),@"Hello World");
}
- (void) Print:(NSString*) str
{
NSLog(@"%@",str);
}
- (IMP)methodForSelector:(SEL)aSelector 函数的作用是通过SEL生成的ID来查找和定位函数的实现地址。 MyPrint(self,@selector(Print:),@"Hello World”); 调用MyPrint函数指针所指向的函数,参数分别为receiver,SEL和要传递给函数的参数。 通过上面的例子,我们明白了通过函数的第一个参数receiver可以区分不同类的函数声明相同的函数。
四 Objective-c消息传递1.
通过上面的一层层剖析和前一节有关类对象的讲解,可能你大概明白了Objective-c中消息的传递方式了。
1.
首先,编译器根据函数声明生成一个唯一函数ID,每个实例变量的第一个成员是isa,它指向类对象,在类对象中保存有该类所拥有的方法列表,通过生成的的函数ID可以找到其对应的函数地址,从而调用函数。如果在当前类对象的函数映射表中没有找到函数的话,就继续搜索其父类中(每个类对象的super_class 存储了父类的类对象地址),如果到达其根类还是没找到的话,会报运行时错误。 其过程如下图所示:
1.
1.
<img src=
"http://www.it165.net/uploadfile/files/2014/0422/20140422192937187.jpg"
alt=
"\" style="
width: 560px; height:
336
.9911504424779px;">
1.
消息的成功传递依赖于两个重要的要素,通过实例中的 isa指针找到实例所属的类对象,然后通过类对象中的消息映射表找到所要调用的函数。
1.
首先通过传递的selector参数找到消息映射表中的函数。然后调用函数,将实例的地址和参数传递给调用的这 个函数。最后返回返回值。
1.
1.
类类型的存在使objective-c拥有了运行时识别,动态创建,序列化等机制。
1.
1.
3
.消息接收者对象(指向消息接收者对象的指针)以及方法中指定的参数传递给方法实现 IMP。
1.
4
.最后,将方法实现的返回值作为该函数的返回值返回。
1.
注:编译器会自动插入调用消息函数objc_msgSend,我们无须在代码中显示调用该消息函数。
1.
1.
五 消息传递小结
1.
到这里,我们已经大致明白了Objective-c 中消息的传递的整个过程。其实如果你熟悉<a href=
"http://www.it165.net/pro/pkmfc/"
target=
"_blank"
class
=
"keylink"
>MFC</a>的话,你会发现Objective-c的运行时和<a href=
"http://www.it165.net/pro/pkmfc/"
target=
"_blank"
class
=
"keylink"
>MFC</a>的RTTI挺像的。
1.编译器会将消息转换为对消息函数 objc_msgSend的调用,该函数有两个主要的参数:消息接收者 receiver 和消息对应的方法ID,即SEL, 同时接收消息不定参数列表。1.
下图是MFC的运行时机制,CRuntimeClass相当于Objectiv-c的object_clas类对象,在CRuntimeClass中有指向基类函数的指针,与MFC不同的是object_class没有类似与m_pNext_ClassMFC成员。
2.objc_masSend 通过 receiver中的isa找到类对象,从而找到 SEL 对应的方法实现 IMP。注:因为不同的类对同一方法可能会有不同的实现,所以找到的方法实现依赖于消息接收者(receiver)。1.
下面再做一下详细消息传递过程:
1.
1.
正因为有像CRuntimeClass和object_class这些类类型的存在才使得它们拥有了运行识别,动态创建,序列化等机制。
下一节将对消息传递做进一步的深层次探究。
1.
1.
0 0
- IOS -运行时 (消息传递 )
- IOS运行时(消息传递)
- IOS -运行时 (消息传递再探究)
- 【iOS】运行时消息传递与转发机制
- ios消息传递机制
- IOS消息传递机制
- IOS消息传递机制
- IOS消息传递
- iOS运行时(runtime)探究三:消息转发
- ios 消息传递 内部调用
- iOS 消息的传递机制
- iOS消息传递机制对比
- iOS消息的传递机制
- IOS消息传递转发机制
- iOS——消息传递
- iOS编程基础-OC(三)-对象和消息传递
- IOS运行时传递对象或者添加属性
- 消息传递(Messaging)
- 0003/1000 最近计划
- c++ 简单位操作
- 大二期末复习java时搜藏的一些面试时会用到的问题
- jquery 回车事件
- 54_leetcode_Spiral Matrix II
- IOS运行时(消息传递)
- Hadoop集群去掉机器后处理
- OCP 1Z0 052 132
- iOS-7-Cookbook
- 简述ajax的原理及实现步骤。
- http-equiv
- 异常与错误区别 Error and Exception
- ivy 简介:
- NYOJ592 spiral grid 【BFS】