您的位置:首页 > 移动开发 > IOS开发

IOS OC objc_msgSend的作用

2015-07-06 00:00 387 查看
摘要: objc_msgSend 函数会依据接受者与选择子的类型来调用适当的方法

一 消息传递

OC中调用方法也叫消息传递(pass a message),消息有名称(name) 或 选择子(selector),可以接受参数,而且可以设定返回值。

OC中向某对象传递消息,会使用动态绑定机制来决定需要调用的方法,在底层,所有方法都是普通的C语言函数,然而对象受到信息之后,究竟调用什么方法则完全完成于运行期决定,甚至可用在程序运行时改变,这些特性使得OC为动态语言。给对象发送消息的写法:

id returnValue = [object messageName:parameter];

returnValue 是 返回值

object 是 接受者(receiver)

messageName 是 选择子(selector)

选择子与参数合起来称为消息。

编译器看到 [object messageName:parameter] 消息后会转换为标准的C语言函数调用,所调用函数是消息传递机制中的核心函数,objc_msgSend,其原型如下:

void objc_msgSend(id self,SEL cmd, …);

这是个“参数个数可变的函数”,能接受多个参数,第一个参数代表 接受者,第二参数代表选择子(SEL 就是选择子的类型,选择子就是方法名),后续参数就是消息中的那些参数,其顺序不变。

二消息调用过程

编译器会把刚才例子中的消息转换成以下函数

id = returnValue = objc_msgSend(someObject,@selector(messageName:),parameter);

objc_msgSend 函数会依据接受者与选择子的类型来调用适当的方法,为了完成此操作,该方法需要在接受者所属的类中搜寻其“方法列表”,如果能找到与选择子名称相符的方法,就跳至其实现代码。若是找不到,那就沿着继承体系继续向上查找,等找适合的方法之后再跳转,如果最终还是找不到相符的方法,那就执行“消息转发”操作(下篇讲),调用一个方法需要很多步骤,为了简化开销,objc_msgSend会将匹配结果缓存在“快速映射表”里面,每个类都有这样一块缓存,在稍后向该类发送选择子相同的消息,执行效率会很快。

三 非objc_message 情况

objc_msgSend_stret 如果待发送的消息要返回结构体,由该函数处理。只有当CPU寄存器能够容纳下返回类型时,该函数才会处理。如果不能容纳,则由另一个函数执行派发

objc_msgSend_fpret 如果返回的浮点数,由该函数处理,在某些架构的CPU中调用函数,需要堆“浮点数寄存器”做特殊处理。

objc_msgSendSuper 如果要给超类发消息,例如[super message:parameter],由该函数处理。

四 尾调用优化

上面提到objc_msgSend 等函数找到调用方法实现后,会“跳转过去”,之所以能这样做,是因为OC 对象的每个方法都可以视为简单的C函数,原型如下

<return_type> Class_selector(id self,SEL _cmd,…)

每个类里都有一张表格,其中的指针会指向这种函数,二选择子的名称则是查表时所用的“键”。ojbc_msgSend 等函数正是通过该表来寻求应该执行的方法并跳转到实现。上面的原型和objc_msgSend 函数很像,是位了利用“尾调用优化”技术,令“跳转到方法实现”操作变得更简单。

如果函数的最后操作是调用另一个函数,就会运用到“尾调用优化”,编译器会生成调转至另一个函数所需的字节码,而且不会像调用堆栈中推入新的“栈幀”,只有当函数最后一个操作是调用其他函数而不会将其返回值另作他用时,才能执行“尾调用优化”,改技术避免了过早发生”栈溢出”现象

五 总结

消息由接受者,选择子以及参数构成,给某个对象发送消息,也就相当于在该对象上 调用方法。

发给某对象的全部消息都需要由 动态消息派发系统 来处理,该系统会查出对应的方法,并执行其代码。

详细请查阅《Effective Objective-c 2.0》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  OC IOS objc_msgSend