我们都知道OC是不支持多继承的,这是因为消息机制名称查找发生在运行时而非编译时,很难解决多个基类可能导致的二义性问题,那么如果我们想要一个类a同时继承类b和类c,我们要如何做才能达到我们想要的结果呢?我们创建三个类ClassA、ClassB、ClassC,A和B分别有两个方法run和walk,假设我们需要让C同时拥有run和walk方法,我们可以通过下面几种方法来达到我们想要的效果。
1、组合
Son添加两个属性father1(- (void)playFootBall),father2(- (void)playBasketball)。那么Son就有了father1和father2的能力。类似于继承了他们两个!!!
@class Father1,Father2;
@interface Father1 : NSObject
- (void)playFootBall;
@end
@interface Father2 : NSObject
- (void)playBasketball;
@end
@interface Son : NSObject
@property (nonatomic,strong)Father1 *father1;
@property (nonatomic,strong)Father2 *father2;
- (void)playBall;
@end
#import "Son.h"
@implementation Father1
- (void)playFootBall{
NSLog(@"playFootBall");
}
@end
@implementation Father2
- (void)playBasketball{
NSLog(@"playBasketball");
}
@end
@implementation Son
- (instancetype)init{
if (self = [super init]) {
self.father1 = [Father1 new];
self.father2 = [Father2 new];
}
return self;
}
- (void)playBall{
[self.father1 playFootBall];
[self.father2 playBasketball];
}
@end
2、delegate和protocol
将C类需要继承的方法以及属性在A和B中各自声明一份协议,C类遵守这两份协议,同时在C类中实现协议中的方法以及属性
@protocol ADelegate
@property (nonatomic,copy)NSString *jinqiu;
- (void)playFootBall;
@end
@protocol BDelegate
@property (nonatomic,copy)NSString *defen;
- (void)playBasketball;
@end
@interface C : NSObject
- (void)playBall;
@end
#import "C.h"
@interface C()<ADelegate,BDelegate>
@end
@implementation C
- (void)playBall{
[self playFootBall];
[self playBasketball];
}
- (void)playFootBall{
self.jinqiu = @"3个进球";
NSLog(self.jinqiu);
}
- (void)playBasketball{
self.defen = @"得了30分";
NSLog(self.defen);
}
@synthesize jinqiu;
@synthesize defen;
@end
3、消息转发(1、快速转发和2、标准转发)
@class Dog;
@interface Dog : NSObject
- (void)eatShi;
@end
@interface Cat : NSObject
- (void)eatFish;
@end
#import "Cat.h"
@implementation Dog
- (void)eatShi{
NSLog(@"吃屎");
}
@end
@implementation Cat
- (void)eatFish{
NSLog(@"吃鱼");
}
//1、快速转发(有快速转发走快速转发)
- (id)forwardingTargetForSelector:(SEL)aSelector{
Dog *dog = [Dog new];
return dog;
}
//2、(没有快速转发走标准消息转发)
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
Dog *dog = [Dog new];
NSMethodSignature *signature = [dog methodSignatureForSelector:aSelector];
return signature;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
SEL selector = [anInvocation selector];
Dog *dog = [Dog new];
if([dog respondsToSelector:selector]){
[anInvocation invokeWithTarget:dog];
}
}
@end
[((Dog*)[Cat new]) eatShi];
2021-03-19 16:37:14.053339+0800 IOS--多继承[79529:1773692] 吃屎
4、类别(category)
类别也可以用来模拟多继承,比如给当前类添加方法,利用runTime来添加属性,方法不表,别人文章Category与Extension有实现,可以参考
5、NSProxy
NSProxy 并没有继承NSObject ,而是实现了NSObject协议
NSProxy 和 NSObject 类都实现了NSObject 协议 ,我们仔细看发现NSProxy并没有init或new方法 ;这个就尴尬了,这个类是一个魏忠贤版的类。。。。。init方法貌似需要子类去实现,也就是这个类注定要被别的类继承。
实现与3、消息转发(1、快速转发和2、标准转发)一样,只不过3、消息转发是继承NSObject ,而现在是使用NSProxy和NSObject有共同的协议,创建NSProxy的子类进行消息转发
结论: 如此看来NSProxy确实更适合实现做为消息转发的代理类, 因为作为一个抽象类, NSProxy自身能够处理的方法极小(仅<NSObject>接口中定义的部分方法), 所以其它方法都能够按照设计的预期被转发到被代理的对象中.而NSObject很多方法自己有实现,例如respondsToSelector:和isKindOfClass,这样的话就不会走消息转发流程。(消息转发是只有当接收者无法处理时才会通过forwardInvocation:来寻求能够处理的对象.)
总结:NSProxy比NSObject更干净。
注意:NSProxy这个基类没有定义默认的init方法.
NSProxy类
image.png
网友评论