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

Posted mqxnongmin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了IOS -执行时 (消息传递再探究)相关的知识,希望对你有一定的参考价值。

一 消息查找优化
	至此。我们已经明确了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消息转发给其他的对象来非常easy的达到这一目的。

更进一步,假设我们希望我们的对象和另外一个类的对象对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做一个具体的对比。


以上是关于IOS -执行时 (消息传递再探究)的主要内容,如果未能解决你的问题,请参考以下文章

iOS开发--探究iOS线程调用栈及符号化

objc_msgSend消息传递学习笔记 – 消息转发

解释器在解析JavaScript代码时对于这两种方式

iOS 未收到来自 Firebase 云消息传递的通知

iOS面试粮食Runtime—消息传递和转发机制Method Swizzling

iOS面试粮食Runtime—消息传递和转发机制Method Swizzling