Objective-C Runtime Reference
Objective-C Runtime Programming Guide
涉及主要文件:objc/message.h,objc/objc-api.h,objc/objc.h,objc/runtime.h
特酷吧[tekuba.net]采用"署名-非商业用途-保持一致"的创作共用协议,使用本文内容请遵循该协议
Objective-C Runtime是Objective-C的基础内容,理解了Objective-C Runtime对于掌握Objective-C的很多技术原理非常有用。特酷吧特别整理了Objective-C Runtime的内容,共六篇,本文是第三篇:
Objective-C Runtime分析(一)-Runtime初步
Objective-C Runtime分析(二)-Class,Method,SEL,IMP
Objective-C Runtime分析(三)-objc_msgSend
Objective-C Runtime分析(四)--Dynamic Method Resolution
Objective-C Runtime分析(五)-Message Forwarding
Objective-C Runtime分析(六)-Type Encodings & Declared Properties

本部分主要参考:https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtHowMessagingWorks.html#//apple_ref/doc/uid/TP40008048-CH104-SW1
通过前两篇的学习,相信你已经对Objective-C Runtime有个一些了解,下面我们就该学习Objective-C Runtime中很重要的“消息”了。
一,obj_msgSend
情景:
Tekuba *tekuba = [[Tekuba alloc] init];
[tekuba url];
执行[tekuba url]时,编译器会自动的转换成objc_msgSend(tekuba, @selector(url));
objc_msgSend的原型是:
id objc_msgSend(id theReceiver, SELtheSelector, ...)
参数分别是消息接收对象,消息对应的方法的标识SEL,以及参数。
在执行objc_msgSend方法时,主要完成了以下几个工作:
The messaging function does everything necessary for dynamic binding:
(1),It first finds the procedure (method implementation) that the selector refers to. Since the same method can be implemented differently by separate classes, the precise procedure that it finds depends on the class of the receiver.
它首先找到 SEL 对应的方法实现 IMP。因为不同的类对同一方法可能会有不同的实现,所以找到的方法实现依赖于消息接收者的类型。
(2),It then calls the procedure, passing it the receiving object (a pointer to its data), along with any arguments that were specified for the method.
然后将消息接收者对象(指向消息接收者对象的指针)以及方法中指定的参数传递给方法实现 IMP。
(3),Finally, it passes on the return value of the procedure as its own return value.
最后,将方法实现的返回值作为该函数的返回值返回。
NOTE:The compiler generates calls to the messaging function. You should never call it directly in the code you write.

二,隐藏参数
When objc_msgSend finds the procedure that implements a method, it calls the procedure and passes it all the arguments in the message. It also passes the procedure two hidden arguments:
(1)The receiving object
(2)The selector for the method
These arguments give every method implementation explicit information about the two halves of the message expression that invoked it. They’re said to be “hidden” because they aren’t declared in the source code that defines the method. They’re inserted into the implementation when the code is compiled.
当objc_msgSend找到方法对应的实现时,它将直接调用该方法实现,并将消息中所有的参数都传递给方法实现,同时,它还将传递两个隐藏的参数:(1)消息的接收者;(2)方法名称 SEL。这些参数帮助方法实现获得了消息表达式的信息。它们被认为是"隐藏"的是因为它们并没有在定义方法的源代码中声明,而是在代码编译时是插入方法的实现中的。
尽管这些参数没有被显示声明,但在源代码中仍然可以引用它们。在方法中可以通过self来引用消息接收者对象,通过选标_cmd来引用方法本身。在下面的例子中,_cmd 指的是strange方法,self指的收到strange消息的对象。

折叠C/C++ Code复制内容到剪贴板
  1. - strange  
  2. {  
  3.     id target = getTheReceiver();  
  4.     SEL method = getTheMethod();  
  5.     if (target == self || mothod == _cmd)  
  6.         return nil;  
  7.     return [target performSelector:method];  
  8. }  


在这两个参数中,self更有用一些。实际上,它是在方法实现中访问消息接收者对象的实例变量的途径。

三,获取方法地址
NSObject 类中的methodForSelector方法可以获取指向方法实现IMP的指针,methodForSelectorL返回的指针和赋值的变量类型必须完全一致,包括方法的参数类型和返回值类型。
下面的例子展示了怎么使用指针来调用setFilled:的方法实现:
void (*setter)(id, SEL, BOOL);
int i;
setter = (void (*)(id, SEL, BOOL))[target methodForSelector:@selector(setFilled:)]; 
for ( i = 0 ; i < 1000 ; i++ )
    setter(targetList[i], @selector(setFilled:), YES);
The first two arguments passed to the procedure are the receiving object (self) and the method selector (_cmd). These arguments are hidden in method syntax but must be made explicit when the method is called as a function.
Using methodForSelector: to circumvent dynamic binding saves most of the time required by messaging. However, the savings will be significant only where a particular message is repeated many times, as in the for loop shown above.
Note that methodForSelector: is provided by the Cocoa runtime system; it's not a feature of the Objective-C language itself.
使用methodForSelector来避免动态绑定将减少大部分消息的开销,但是这只有在指定的消息被重复发送很多次时才有意义,例如上面的for循环。 [特酷吧的理解就是在基于NSObject的对象中,都有一个Class属性,维护了一个方法缓存,当多次调用的时候,是从缓存中找IMP,自然就比较快]。
注意,methodForSelector是Cocoa运行时系统的提供的功能,而不是Objective-C语言本身的功能。
转载请注明来自特酷吧,本文地址:www.tekuba.net/program/338/
推荐阅读:
IOS7运动视觉效果[UIInterpolatingMotionEffect]
IOS CoreAnimation核心动画(1)-CALayer和CAAnimation初步
iOS下TTS语音合成的几种方案
iOS 图片平铺和拉伸
iOS Quartz2D字体描边加粗等

想及时获取特酷吧的更新?想了解iOS,android开发最新技术动态,点击或扫描下方二维码下载“多识阅读”App,丰富的iOS,Android,Web等领域开发者博客随你订阅。

多识阅读