一 消息查找优化
至此。我们已经明确了Objective-c中大致的消息传递过程,我们发现假设每次函数调用都经历上面的过程(。那函数调用的效率就会非常低,尤其是当类的继承层次非常多的时候。它须要一层层的查找其效率将会更低,为了加快查找调用的速度,Objective-c对消息查找做了优化。
从前一节的类对象我们知道它含有一个 struct objc_cache *cache成员,这个缓存就是为了提高查找的效率的。每一个类都有自己的缓存,同一时候包含继承的方法和在该类中定义的方法。
当我们在查找IMP 时:
1.首先去该类的方法 cache 中查找,假设找到了就返回它
2.假设没有找到,就去该类的方法列表中查找。假设在该类的方法列表中找到了,则将 IMP 返回,并将它增加cache中缓存起来。依据近期使用原则。这种方法再次调用的可能性非常大。缓存起来能够节省下次调用再次查找的开销。
关于消息转发的作用。能够考虑例如以下情景:假设,我们须要设计一个能够响应negotiate消息的对象,而且能够包含其他类型的对象对消息的响应。 通过在negotiate方法的实现中将negotiate消息转发给其他的对象来非常easy的达到这一目的。
更进一步,假设我们希望我们的对象和另外一个类的对象对negotiate的消息的响应全然一致。
一种可能的方式就是让我们的类继承其他类的方法实现。 然而。有时候这样的方式不可行。由于我们的类和其他类可能须要在不同的继承体系中响应negotiate消息。
尽管我们的类无法继承其他类的negotiate方法,但我们仍然能够提供一个方法实现,这种方法实现仅仅是简单的将negotiate消息转发给其他类的对象,就好像从其他类那儿“借”来的现一样。例如以下所看到的:
- negotiate {
if ([someOtherObject respondsToSelector:@selector(negotiate)])
return [someOtherObject negotiate];
这样的方式显得有欠灵活。特别是有非常多消息都希望传递给其他对象时,我们就必须为每一种消息提供方法实现。此外,这样的方式不能处理未知的消息。当我们写下代码时。全部我们须要转发的消息的集合都必须确定。
然而,实际上,这个集合会随着执行时事件的发生,新方法或者新类的定义而变化。
forwardInvocation:消息给这个问题提供了一个更特别的。动态的解决方式:当一个对象由于没有相应的方法实现而无法响应某消息时,执行时系统将通过forwardInvocation:消息通知该对象。
每一个对象都从NSObject类中继承了forwardInvocation:方法。然而,NSObject中的方法实现仅仅是简单地调用了doesNotRecognizeSelector:。
通过实现我们自己的forwardInvocation:方法,我们能够在该方法实现中将消息转发给其他对象。
要转发消息给其他对象,forwardInvocation:方法所必须做的有:
1.决定将消息转发给谁。而且
2.将消息和原来的參数一块转发出去
消息能够通过invokeWithTarget:方法来转发:
- (void) forwardInvocation:(NSInvocation *)anInvocation
{
if ([someOtherObject respondsToSelector:[anInvocation selector]])
[anInvocation invokeWithTarget:someOtherObject];
else
[super forwardInvocation:anInvocation];
}
转发消息后的返回值将返回给原来的消息发送者。您能够将返回不论什么类型的返回值,包含: id。结构体,浮点数等。 forwardInvocation:方法就像一个不能识别的消息的分发中心。将这些消息转发给不同接收对象。或者它也能够象一个运输站将全部的消息都发送给同一个接收对象。它能够将一个消息翻译成另外一个消息,或者简单的"吃掉“某些消息。因此没有响应也没有错误。forwardInvocation:方法也能够对不同的消息提供相同的响应,这一切都取决于方法的具体实现。该方法所提供是将不同的对象链接到消息链的能力。
所以。假设我们希望一个对象将negotiate消息转发给其他对象,则这个对象不能有negotiate方法。
否则。forwardInvocation:将不可能会被调用。