IOS -运行时 (消息传递再探究)

来源:互联网 发布:局域网语音通话软件 编辑:程序博客网 时间:2024/06/07 10:13
一 消息查找优化
至此,我们已经明白了Objective-c中大致的消息传递过程,我们发现如果每次函数调用都经历上面的过程(,那函数调用的效率就会很低,尤其是当类的继承层次很多的时候,它需要一层层的查找其效率将会更低,为了加快查找调用的速度,Objective-c对消息查找做了优化。
从前一节的类对象我们知道它含有一个 struct objc_cache *cache成员,这个缓存就是为了提高查找的效率的。每个类都有自己的缓存,同时包括继承的方法和在该类中定义的方法。当我们在查找IMP 时:
     1.首先去该类的方法 cache 中查找,如果找到了就返回它
     2.如果没有找到,就去该类的方法列表中查找。如果在该类的方法列表中找到了,则将 IMP 返回,并将它加入cache中缓存起来。根据最近使用原则,这个方法再次调用的可能性很大,缓存起来可以节省下次调用再次查找的开销。
     3.如果在该类的方法列表中没找到对应的 IMP,在通过该类结构中的 super_class指针在其父类结构的方法列表中去查找,直到在某个父类的方法列表中找到对应的IMP,返回它,并加入cache中。

     4.如果在自身以及所有父类的方法列表中都没有找到对应的 IMP,则进入下文中要讲的消息转发流程。


二 消息转发
      给一个对象发送它不能处理的消息会得到出错提示,然而,Objective-C运行时系统在抛出错误之前,会给消息接收对象发送一条特别的消息forwardInvocation 来通知该对象,该消息的唯一参数是个NSInvocation类型的对象——该对象封装了原始的消息和消息的参数。

我们可以实现forwardInvocation:方法来对不能处理的消息做一些默认的处理,也可以将消息转发给其他对象来处理,而不抛出错误。
       关于消息转发的作用,可以考虑如下情景:假设,我们需要设计一个能够响应negotiate消息的对象,并且能够包括其它类型的对象对消息的响应。 通过在negotiate方法的实现中将negotiate消息转发给其它的对象来很容易的达到这一目的。      更进一步,假设我们希望我们的对象和另外一个类的对象对negotiate的消息的响应完全一致。一种可能的方式就是让我们的类继承其它类的方法实现。 然而,有时候这种方式不可行,因为我们的类和其它类可能需要在不同的继承体系中响应negotiate消息。       虽然我们的类无法继承其它类的negotiate方法,但我们仍然可以提供一个方法实现,这个方法实现只是简单的将negotiate消息转发给其他类的对象,就好像从其它类那儿“借”来的现一样。如下所示:- negotiate  {    if ([someOtherObject respondsToSelector:@selector(negotiate)])        return  [someOtherObject negotiate];
    return self;
}
      这种方式显得有欠灵活,特别是有很多消息都希望传递给其它对象时,我们就必须为每一种消息提供方法实现。此外,这种方式不能处理未知的消息。当我们写下代码时,所有我们需要转发的消息的集合都必须确定。然而,实际上,这个集合会随着运行时事件的发生,新方法或者新类的定义而变化。     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:方法也可以对不同的消息提供同样的响应,这一切都取决于方法的具体实现。该方法所提供是将不同的对象链接到消息链的能力。
注意: forwardInvocation:方法只有在消息接收对象中无法正常响应消息时才会被调用。 所以,如果我们希望一个对象将negotiate消息转发给其它对象,则这个对象不能有negotiate方法。否则,forwardInvocation:将不可能会被调用。

三 小结
        现在当我们回过头来在看http://blog.csdn.net/zhangzhebjut/article/details/24134863中的实例应该明白了IOS中整个函数的调用流程。IOS的运行时还是挺强大的,通过对运行时的学习,对Objective-c类型系统有一个更加深刻的了解。
         其实如果熟悉Python的人应该也知道,Python是一个全动态的语言,它的类型系统和Objective-c有些相像,有时间给我会将其与Objective-c做一个详细的对照。

0 0
原创粉丝点击