Objective-C的“多继承”——消息转发
当单继承不够用,很难为问题域建模时,我们通常都会直接想到多继承。多继承是从多余一个直接基类派生类的能力,可以更加直接地为应用程序建模。但是Objective-C不支持多继承,由于消息机制名字查找发生在运行时而非编译时,很难解决多个基类可能导致的二义性问题。
不过其实 Objective-C 也无需支持多继承,我们可以找到如下几种间接实现多继承目的的方法:
- 消息转发
- delegate和protocol
- 类别
消息转发
当向someObject发送某消息,但runtime system在当前类和父类中都找不到对应方法的实现时,runtime system并不会立即报错使程序崩溃,而是依次执行下列步骤:
分别简述一下流程:
1.动态方法解析 向当前类发送 resolveInstanceMethod: 信号,检查是否动态向该类添加了方法。(迷茫请搜索:@dynamic)
2.快速消息转发 检查该类是否实现了 forwardingTargetForSelector: 方法,若实现了则调用这个方法。若该方法返回值对象非nil或非self,则向该返回对象重新发送消息。
3.标准消息转发 runtime发送methodSignatureForSelector:消息获取Selector对应的方法签名。返回值非空则通过forwardInvocation:转发消息,返回值为空则向当前对象发送doesNotRecognizeSelector:消息,程序崩溃退出。
顾名思义,我们可以利用上述过程中的2、3两种方式来完成消息转发。
快速消息转发
快速消息转发的实现方法很简单,只需要重写
- (id)forwardingTargetForSelector:(SEL)aSelector
举个栗子
//Teacher类需要实现将消息转发给Doctor:
- (id)forwardingTargetForSelector:(SEL)aSelector { Doctor *doctor = [[Doctor alloc]init]; if ([doctor respondsToSelector:aSelector]) { return doctor; } return nil; }
标准消息转发
标准消息转发需要重写
methodSignatureForSelector:
forwardInvocation:
举个栗子
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature* signature = [super methodSignatureForSelector:aSelector]; if (signature==nil) { signature = [someObj methodSignatureForSelector:aSelector]; } NSUInteger argCount = [signature numberOfArguments]; for (NSInteger i=0 ; i<argCount ; i++) { } return signature; } - (void)forwardInvocation:(NSInvocation *)anInvocation { SEL seletor = [anInvocation selector]; if ([someObj respondsToSelector:seletor]) { [anInvocation invokeWithTarget:someObj]; } }
两种消息转发方式的比较
- 快速消息转发:简单、快速、但仅能转发给一个对象
- 标准消息转发:稍复杂、较慢、但转发操作实现可控,可以实现多对象转发