iOS知识小集之为什么objc_msgSend()是用汇编实现的
消息发送
在使用Objective-C
调用方法时,我们将其称之为消息发送,这与我们用的C
、C++
等调用函数的说法不一样,原因就是Objective-C
调用方法时,并不是简单的会在编译时得到函数指针,调用时直接使用该函数指针调用就行(C++
有虚函数,包含一个v-table
,可以实现简单的多态),而是会在调用的时候,运行时的去查找函数实现,比如,当我们发送[objc foo]
时,编译器会将其转化为objc_msgSend(objc, @selector(foo))
(注意,不一定都是转化为objc_msgSend
,根据发送对象和返回类型,可转化为objc_msgSendSuper
,objc_msgSendSuper_stret
等),objc_msgSend
方法负责查找函数实现并调用返回结果,我们知道,Objc Runtime
是开源的,所以我们可以看一下源代码objc_msgSend
的实现逻辑。
objc_msgSend()使用汇编实现
源码可参见objc_msgSend源码,我们发现,竟然不是用C
实现的,而是使用的汇编语言,总结来说,原因有二:
- 我们无法定义一个
C
函数,可以有可变的参数(可变参数是可以实现的,参考printf
函数)并且可以调用任意的C
函数指针,因为函数指针类型是在是无穷无尽的,根本就无法预先全部定义出来。 - 使用汇编另一个很重要的原因就是速度,首先,汇编就比
C
快,其次,通过使用汇编,可以免去大量局部变量拷贝的操作,参数会直接被存放在寄存器中,当找到IMP
时,参数已经保存在了寄存器中,可以直接使用。
objc_msgSend()步骤总结
objc_msgSend
步骤:
- 获取传递进来的类对象
- 获取类用来缓存方法的cache
- 使用
selector
在cache中查找 - 如果cache中查找不到,则跳转到C代码(
_class_lookupMethodAndLoadCache3
),进行slow search - 调用方法的IMP