参考博客
多继承可以允许子类从多个父类派生,而Objective-C并不支持多继承,但我们仍可间接实现。
Objective-C实现多继承主要可以通过协议、分类、消息转发来实现。我们来总结一下其使用以及优缺点。
1. 组合方式实现
person类继承与singer和dancer类,则可以让person继承与singer,然后实例化一个dancer的对象,就可以即调用singer又可以调用dancer的方法。
外部调用时就是[person.dancer 方法名]
2. 通过协议实现
协议只能提供接口,不能提供实现,所以要在子类中添加想应的实现。(我感觉只是让方法更加模块化,更加清晰,实现还是写在当前类)
3. 通过分类和三次拯救中的第二次拯救
在外部调用可以是[person 方法名]
把方法名写在分类中,外部就可以直接以person的对象调用方法而不报错,此时只是外部可以调用而不报错,但并没有方法的实现。
在三次拯救的第二次拯救(备用接收者)中,把该方法的实现转交给dance类,这样[perosn dance]也可以实现dancer类的dance方法。
4. 协议和NSProxy实现
主要是让当前类转变为singer或者dancer。
现在再说 NSProxy, 这才是真的代理
NSProxy:
测试demo
这个类是和 NSObject 平起平坐的, 而且这个类没有 init 方法,也就是说,它只可以开辟一块内存空间,而不能初始化. 那么,我怎么样这个类可以变成任意一个类呢?
主要有这样几步,
- 我先设置一个类 PYRProxy, 继承自 NSProxy
- 为 YFProxy 设置一个 NSObject 属性
- 自定义一个转换方法,相当于给 NSObject 属性赋值
- 然后通过这个属性获得调用方法的方法签名
- 为调用设置目标
- 调用
详见协议和 NSProxy 实现多继承
里面步骤比较清楚。
- 一个继承自NSProxy的PYRProxy类,用于在类中自由转换
.h文件
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface PYRProxy : NSProxy
@property (nonatomic, strong)NSObject *object;
- (id)transformToObject:(NSObject *)obj;
@end
NS_ASSUME_NONNULL_END
.m文件
#import "PYRProxy.h"
@implementation PYRProxy
- (id)transformToObject:(NSObject *)obj {
self.object = obj;
return self.object;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
NSMethodSignature *methodSignature;
if (self.object) {
methodSignature = [self.object methodSignatureForSelector:sel];
} else {
methodSignature = [super methodSignatureForSelector:sel];
}
return methodSignature;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
if (self.object) {
[invocation setTarget:self.object];
[invocation invoke];
}
}
@end
- 外部调用
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
Person *person = [[Person alloc] init];
Animal *animal = [[Animal alloc] init];
PYRProxy *proxy = [PYRProxy alloc];
[proxy transformToObject:person];
[proxy performSelector:@selector(personSay)];
[proxy transformToObject:animal];
[proxy performSelector:@selector(animalSay)];
}
@end