//联系人:石虎QQ: 1224614774昵称:嗡嘛呢叭咪哄
一、OC 消息机制原理
/**
注意点:
1.在 OC 中,message与方法是在执行阶段绑定的,而不是编译阶段。
2.可以说[a func]这样一个调用,在编译阶段,编译器并不知道 func要执行哪段代码。
3.[a func]会被转换为objc_msgSend(a,"someFunc"),字面的意思也很容易理解,就是给a这个instance,发“someFunc”这个消息,以selector的形式。在运行阶段,执行到上述的objc_msgSend这个函数时。
4.函数内部会到a对应的内存地址,寻找func这个方法的地址,并执行。
5.如果找不到,就会抛一个“unknown selector sent to instance”的异常。
注意:(比如.h中声明了方法,但.m中没有实现,就可以重现这个错误)所以严格意义上来讲,任何Objective C的函数调用,编译阶段的表现,都只能算一种“发消息”的行为。
*/
二、为什么使用汇编语言
其实在objc-msg-x86_64.s中包含了多个版本的objc_msgSend方法,它们是根据返回值的类型和调用者的类型分别处理的:
objc_msgSendSuper:向父类发消息,返回值类型为id
objc_msgSend_fpret:返回值类型为floating-point,其中包含objc_msgSend_fp2ret入口处理返回值类型为longdouble的情况
objc_msgSend_stret:返回值为结构体
objc_msgSendSuper_stret:向父类发消息,返回值类型为结构体
当需要发送消息时,编译器会生成中间代码,根据情况分别调用objc_msgSend, objc_msgSend_stret, objc_msgSendSuper,或objc_msgSendSuper_stret其中之一。
这也是为什么objc_msgSend要用汇编语言而不是OC、C或C++语言来实现,因为单独一个方法定义满足不了多种类型返回值,有的方法返回id,有的返回int。考虑到不同类型参数返回值排列组合映射不同方法签名(method signature)的问题,那switch语句得老长了。
这些原因可以总结为Calling Convention,也就是说函数调用者与被调用者必须约定好参数与返回值在不同架构处理器上的存取规则,比如参数是以何种顺序存储在栈上,或是存储在哪些寄存器上。
除此之外还有其他原因,比如其可变参数用汇编处理起来最方便,因为找到IMP地址后参数都在栈上。
要是用C++传递可变参数那就悲剧了,prologue机制会弄乱地址(比如i386上为了存储ebp向后移位4byte),最后还要用epilogue打扫战场。而且汇编程序执行效率高,在Objective-CRuntime中调用频率较高的函数好多都用汇编写的。
谢谢!!