首页 > 代码库 > 第十一条理解objc_masgSend的作用

第十一条理解objc_masgSend的作用

Objetive-C最基本的的东西就是它的消息机制。Objective-C运行时的最基本的东西就是 objc_msgSend, 它就是负责发送一个消息给对象的C函数。

 
当你写下面这样的代码时:  [tableView cellForRowAtIndexPath:indexPath];
 
编译器实际上把它转换成下面这样的C函数调用  objc_msgSend(tableView, @selector(cellForRowAtIndexPath:), indexPath);
 

objc_msgSend的返回类型是id. 如果你需要 让一个方法调用, 返回一个原始的对象(或者C结构体)而不是 对象指针, 那应该怎么办呢?

执行下面人为捏造的代码(因为一般不会直接调用msgSend),会返回一个编译器错误,因为类型不匹配

UIView *view = [[UIView alloc] initWithFrame:CGRectZero];CGRect rect = objc_msgSend(view, @selector(frame));

如果你将第2行,改成 [view frame]
编译器 不会 把它转换成 msgSend, 而是调用 objc_msgSend_stret

objc_msgSend_stret是一个objc_msgSend的替代版本, 用来返回一个结构体。stret就是 STruct RETurn的缩写。
另外一个相关的objc_msgSend_fret 返回一个Floating-pointer

 
函数声明
void objc_msgSend_stret(void *stretAddr, id theReceiver, SEL theSelector, ....)
 
几个特殊方法

objc_msgSend_stret
如果待发送的消息要返回结构体,那么可交由此函数处理。只有当CPU的寄存器能够容纳得下消息返回类型时,这个函数才能处理此消息。若是返回值无法容纳于CPU寄存器中(比如说返回的结构体太大了),那么就由另一个函数执行派发。此时,那个函数会通过分配在栈上的某个变量来处理消息所返回的结构体。

objc_msgSend_fpret
如果消息返回的是浮点数,那么可交由此函数处理。在某些架构的CPU中调用函数时,需要对“浮点数寄存器”(floating-point register)做特殊处理,也就是说,通常所用的objc_msgSend在这种情况下并不合适。这个函数是为了处理x86等架构CPU中某些令人稍觉惊讶的奇怪状况。

objc_msgSendSuper
如果要给超类发消息,例如[super message:parameter],那么就交由此函数处理。也有另外两个与objc_msgSend_stret和objc_msgSend_fpret等效的函数,用于处理发给super的相应消息。

 

 
详解objc_msgSend】原文:http://www.cnblogs.com/tekkaman/archive/2013/05/23/3094549.html

 1、为了性能,objc_msgSend用汇编写成。存在于objc-msg-x86_64.s中。

  技术分享

 2、在上图代码中可以看到,objc_msgSend被分为2个过程:1)在cache中寻找SEL。2)在MethodTable寻找SEL。

 3、CacheLookup中,不断地拿SEL与cache中的缓存比较,比较失败,则跳转到 LCacheMiss标签继续在MethodTable中搜索。

  技术分享

  如果想手动查找cache,则需要调用_cache_getimp函数(汇编实现),此函数是个对外接口层,用于保存与准备环境。

  技术分享

  _cache_getImp在头文件中objc-private.h中,链接后objc/c代码可以直接调用。

  技术分享

 4、MethodTableLookup 是个接口层宏,主要用于保存环境与准备参数,来调用 __class_lookupMethodAndLoadCache3函数(此函数实现于objc-class.mm)。

  技术分享

 5、__class_lookupMethodAndLoadCache3函数也是个接口层(C编写),此函数提供相应参数配置,实际功能在lookUpMethod函数中。

  技术分享

 6、lookUpMethod函数实现遍历method_list_t,从子类开始,一直遍历到根类。此函数代码较大,不贴图了。文件在objc-class中。

第十一条理解objc_masgSend的作用