iOS 程序指南:在 Objective-C 中模仿多继承
首先,不得不说的是。这个技巧虽然一点也不复杂,但是对于程序员对自己代码的理解有非常高的要求。Objective-C 不支持多继承毕竟有它的原因。多继承使得我们可以把许许多多不同对象的特性组合到一起,这个的结果大多会使得你的对象变的庞大,并且具有多个接口。而我们在 iPhone 开发中更经常使用而且更适应的是精细的,只为完成自己功能而设计的对象。事实上,现在所要介绍的方法也只是多继承的一个模仿。它也倾向于鼓励你的对象变的精巧,各司其职。而这一切都是由 Objective-C 的运行库提供的。
当然,我们为什么要使用多继承呢?多继承在某些特定的时候有非常显著的好处。比如当我们设计游戏的时候(我特别喜欢用星际争霸来做例子),我们设计了一个对象名为基地,然后有第二个对象名为母舰核心。很显然的是,这两个对象应该继承不同的父类:建筑与单位。但是某一天,我们的游戏设计人员认为,应该给母舰核心一个技能,让他能把自己的攻击能力转移到基地身上,这样基地就可以攻击了。这个时候我们应该怎么办呢?我们可以为基地单独写一个攻击方法。或者我们可以简单的,(在多继承的情况下)让基地继承于母舰核心,这样就可以借用母舰核心的部分方法了。
当然,事实上只要是游戏就是和 Objective-C 不沾边的。不过类似的场景可以有很多。Objective-C 理解这一点,然后为我们提供了一个解决方案。也就是运行时的消息转发。
- (void) forwardInvocation:(NSInvocation *)anInvocation;
它的工作原理是这样的。当一个对象收到一条它所未定义的消息的时候,它并不是第一时间抛出异常然后让调用栈去捕获,而是提供了第二次机会,它会调用 forwardInvocation: 这个方法,尝试把这条消息交给其他对象处理。(其他你定义的,这个对象里有 reference 的对象。)NSInvocation 这个类里面封装了消息名称,以及传递的参数这一系列信息。这样的话,我们就可以根据消息的性质,把这个消息移交给其他对象。其返回值也会传回给我们,这样,我们自己的对象的工作方式就和远端的另一个对象显得一致了。
这样做有什么好处呢?第一,如果你的对象已经定义了这个方法,那么 forwardInvocation 是不会被触发的,这点就和函数的重写有些类似。第二,相比自己重新写一个方法,在开发者的角度而言,你所寻求的其他对象很可能不只能够处理这一个消息,很有可能它还会处理其他你理应当处理但是只在运行时才能发现的问题(比如在某个时间点之后对方对自己提供的对象进行了升级。)所以,利用这样一个运行时消息转发的机制,可以很不错的模仿多继承的功能,顺便保留了 Objective-C 的精巧特性。
第三,这个方法为我们提供了一个非常优良的模式。也就是 Cocoa 框架里面,NSObject 之外的另一大根类,NSProxy 所使用的模式。有一些时候,我们会遇到一些很庞大的对象。它可能是一个单例,可能是其他的。大多数时候我们只需要获得它的某些描述信息(想到了什么,流媒体还是网络?)而不需要使用它。因为初始化这样一个类消耗的资源太大了,所以我们希望尽量延迟这个操作:最好的情况是不要做!在这个时候,我们就可以设计一个前端的轻量级对象,它可以应对大多数接受到的消息,而当自己接受到未定义的消息的时候,再将其转发给背后的庞大的对象:这个时候才会调用这个对象的单例,进行初始化。从使用者的角度上讲,这个前端的轻量级对象的表现和预期的一模一样。你看,这是不是很酷?
当然,这样一个方法不可能没有它的陷阱。首先,respondsToSelector 等系列方法依然会认为自己不能对这一些准备转发的消息做出反应。第二,抛出异常的对象不再是你的对象而是远端的那个对象。所以 Oops,最开始说什么来着?要利用这个技巧,必须得对自己的对象以及自己准备转发消息的目标对象有深刻的了解才行。就正如苹果官方文档所言:如果不是实在没辙,千万别用它!
补充:移动开发 , IOS ,