Messaging
编译器将 [receiver message] 编译成:objc_msgSend(receiver, selector); 若有参数的话则是:objc_msgSend(receiver, selector, arg1, arg2, …)。
在动态绑定时,消息函数作的事情:
1. 根据receiver类,找到selector所指的procedure
2.调用找到的procedure, 并将收到的数据对象和参数传递给它
3.最后,将procedure返回的对象作为自己的对象返回
注意:编译器能生成消息函数的调用,但我们不应在代码里直接去调用objc_msgSend.
Messging 依赖于编译类时产生的一个数据结构,该结构包含:
1.A pointer to the superclass.
2.A class dispatch table.This table has entries that associate method selectors with the class-specific addresses of the mesthod they identify.通过函数名字和函数的地址关联在一起。
当一个新对象被创建,内存分配好,变量初始化好后,就会有一个叫 isa 的指针指向该类的类数据结构。通过isa, 就能访问该类以及通过该类访问他的父类。
当调用一个method 时,先查当前类的dispatch table, 没有查到则查父类的,依此直到NSObject。
Using Hidden Arguments
当运行时系统调用objc_msgSend时,还会传递两个隐含的参数:
1.The receiving object. -->self
2.The selector for the method. -->_cmd
- strange
{
id target = getTheReceiver();
SEL method = getTheMethod();
if( target == self || method == _cmd)
return nil;
return [target performSelector:method];
}
Getting a Method Address
在循环调用同一个函数多次时,为提高效率,也可以同NSObject的methodForSelector: 直接获得函数的调用地址进行调用。
void (*setter) (id, SEL, BOOL);
int i;
setter = (void (*)(id, SEL, BOOL))[target methodForSelector:@selector(setFiled:)];
for( i=0; i<100; i++){
setter(targetList[i], @selector(setFiled:), YES);
}
The first two arguments passed to the procedure are the receving object(self) and the method selector(_cmd).
methodForSelector: 是由Cocoa runtime system 提供的。