Message

转自: http://my.oschina.net/amoyai/blog/92191

iOS的消息机制和动态绑定

Class SQSYAPIProtalClass = NSClassFromString(@"SQSYAPIProtal");
SEL initFunc = NSSelectorFromString(@"initSQSYSDKWithGameID:gameKey:");

if (dict) 
{
    NSString* configGameID  = [dict objectForKey:@"GameID"];
    NSString* configGameKey = [dict objectForKey:@"GameKey"];
    ((void(*)(id, SEL,NSString*, NSString*))objc_msgSend)(SQSYAPIProtalClass, initFunc, configGameID, configGameKey);
} 
else 
{
    ((void(*)(id, SEL,NSString*, NSString*))objc_msgSend)(SQSYAPIProtalClass, initFunc, gameID, gamekey);
}


// 回调
if ([self.beginRefreshingTaget respondsToSelector:self.beginRefreshingAction]) {
    ((void(*)(id, SEL, id))objc_msgSend)(self.beginRefreshingTaget, self.beginRefreshingAction, self);
}

最近见到这两段代码,对这个objc_msgSend这个C类型的方法相当陌生,但是望文生义, objc  msg send, 就知道是和消息机制有关的方法。

在:

/** 
 * Sends a message with a simple return value to an instance of a class.
 * 
 * @param self A pointer to the instance of the class that is to receive the message.
 * @param op The selector of the method that handles the message.
 * @param ... 
 *   A variable argument list containing the arguments to the method.
 * 
 * @return The return value of the method.
 * 
 * @note When it encounters a method call, the compiler generates a call to one of the
 *  functions \c objc_msgSend, \c objc_msgSend_stret, \c objc_msgSendSuper, or \c objc_msgSendSuper_stret.
 *  Messages sent to an object’s superclass (using the \c super keyword) are sent using \c objc_msgSendSuper; 
 *  other messages are sent using \c objc_msgSend. Methods that have data structures as return values
 *  are sent using \c objc_msgSendSuper_stret and \c objc_msgSend_stret.
 */
OBJC_EXPORT id objc_msgSend(id self, SEL op, ...)
    __OSX_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);


看头文件的文档注释,函数作用看不懂,但是参数的类型可以大体看得懂:

分别是:1.一个类的实例的指针来接收这个消息    2.一个操作方法来处理这个消息    3.该方法的一个参数列表

其中前两项是必选的: 接收者 和 方法名 

[self justTestLog];

- (void)justTestLog
{
<span style="white-space:pre">	</span>NSLog(@"just Test Log");
}

例如上面非常简单的一个接受者 和 方法名 [self justTestLog]

在objc_msgSend方法中,就会按照参数格式转换为:objc_msgSend(self,  NSSelectorFromString(@"justTestLog") );

如果是有参数的情况下,例如:

[self justTestLog:@"lxt" and:@"man"];

- (void)justTestLog:(NSString* )name andSex:(NSString* )sex
{
	NSLog(@"just Test Log and :%@ and :%@", name, sex);
}

这个时候就会加上参数列表:

objc_msgSend( self, NSSelectorFromString(@"justTestLog: andSex:") , name, sex ) 


该方法会按照这样的操作顺序来完成动态绑定:

1.查找selector 即方法的实现来完成对receiver的操作 (不同的receiver对相同的selector可能会有着不同的实现效果,这个就是多态性)

2.如果没有参数,直接进行第三步,如果方法存在参数,则传递参数

3.使用selector在对应的receiver下的返回值作为自己的返回值,并返回它


消息传递的关键是,编译器构建每个类和对象时所采用的数据结构。每个类都包含以下两个必要元素:

1.一个指向父类的指针  2.一个调度表(dispatch table)。该调度表将类的selector与方法的实际内存地址关联起来

每个对象都有一个指向所属类的指针isa ( instance selector address )。通过该指针,对象可以找到它所属的类,也就找到了其全部父类:


 当向一个对象发送消息时,objc_msgSend方法根据对象的isa指针找到对象的类,然后在类的调度表(dispatch table)中查找selector。如果无法找到selector,objc_msgSend通过指向父类的指针找到父类,并在父类的调度表(dispatch table)中查找selector,以此类推直到NSObject类。一旦查找到selector,objc_msgSend方法根据调度表的内存地址调用该实现。 通过这种方式,message与方法的真正实现在执行阶段才绑定。


为了保证消息发送与执行的效率,系统会将全部selector和使用过的方法的内存地址缓存起来。每个类都有一个独立的缓存,缓存包含有当前类自己的 selector以及继承自父类的selector。查找调度表(dispatch table)前,消息发送系统首先检查receiver对象的缓存。


缓存命中的情况下,消息发送(messaging)比直接调用方法(function call)只慢一点点点点。


这里还没完全理解,等日后再慢慢理解吧!



“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值