0%

协议和 NSProxy 实现多继承

OC 中一个类只有一个父类, 这就是单一继承, 但是我们可以用协议和 NSProxy 实现多继承
先说协议, 协议我们用的最多的地方,就是代理,其实代理不叫代理,叫委托, 这里就不多说了,相信大家都很熟了

那么 protocol 这个东西,是可以遵守多个的,遵守了之后,实现 protocol 中的方法,就OK 了,就是这么简单,轻松, easy

比如我有两个协议, 分别是 YFPerson,YFChild

1
2
3
4
5
6
7
8
9
10
11
12
#import <Foundation/Foundation.h>

@protocol YFPerson <NSObject>
@required
@property (nonatomic,copy,readonly)NSString *name;
- (NSInteger) age;
- (void)eat;
- (void)sleep;
@optional
- (void)play;
- (void)setName:(NSString *)newName;
@end
1
2
3
4
5
6
7
8
9
#import <Foundation/Foundation.h>

@protocol YFChild <NSObject>
@required
- (NSString *)nickname;
- (void)introduceMyselfWithName:(NSString *)name nickname:(NSString *)nickname age:(NSInteger)age;
@optional
- (void)study;
@end

那么, 我在新创建的一个 YFStudent 类中, 只要遵守上面两个协议, 实现协议里的方法, 就可以在一个类中,实现多个协议中的方法了.

YFStudent.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- (NSString *)nickname 
{
return @"龙儿";
}

- (NSInteger)age
{
return 19;
}

- (void)sleep{
NSLog(@"sleep");
}

- (void)eat{
NSLog(@"eat");
}

- (void)introduceMyselfWithName:(NSString *)name nickname:(NSString *)nickname age:(NSInteger)age
{
NSLog(@"我叫%@,小名%@,今天%@岁了", name,nickname,@(age));
}

这样, 我在控制器的 viewDidLoad 方法中,创建 YFStudent 对象, 然后就可以调协议中的任何方法了

1
2
3
4
5
6
7
8
9
- (void)viewDidLoad {
[super viewDidLoad];

YFStudent *student = [[YFStudent alloc]init];
student.name = @"小龙女";
[student eat];
[student sleep];
[student introduceMyselfWithName:student.name nickname:student.nickname age:student.age];
}
现在再说 NSProxy, 这才是真的代理,不信去翻词典

这个类是和 NSObject 平起平坐的, 而且这个类没有 init 方法,也就是说,它只可以开辟一块内存空间,而不能初始化. 那么,我怎么样这个类可以变成任意一个类呢?

  1. 主要有这样几步,
  2. 我先设置一个类 YFProxy, 继承自 NSProxy
  3. YFProxy 设置一个 NSObject 属性
  4. 自定义一个转换方法,相当于给 NSObject 属性赋值
  5. 然后通过这个属性获得调用方法的方法签名
  6. 为调用设置目标
  7. 调用

我一步步说一遍

  1. 为外界暴露一个变身方法:

    1
    2
    3
    4
    5
    6
    7
    #import <Foundation/Foundation.h>

    @interface YFProxy : NSProxy

    - (id)transformToObject:(NSObject *)object;

    @end
  2. 设置一个 NSObject 属性

    1
    2
    3
    4
    5
    6
    7
    #import "YFProxy.h"

    @interface YFProxy ()

    @property (nonatomic,strong)NSObject *object;

    @end
  3. 实现变身方法

    1
    2
    3
    4
    5
    - (id)transformToObject:(NSObject *)object
    {
    self.object = object;
    return self.object;
    }
  4. 重写- (NSMethodSignature *)methodSignatureForSelector:(SEL)see方法获得方法签名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
    {
    NSMethodSignature *methodSignature;

    if (self.object) {
    methodSignature = [self.object methodSignatureForSelector:sel];

    }else{

    methodSignature = [super methodSignatureForSelector:sel];
    }
    return methodSignature;
    }
  5. 重写- (void)forwardInvocation:(NSInvocation *)invocation方法改变调用对象,也就是说,让消息实际上发给真正的实现这个方法的类

    1
    2
    3
    4
    5
    6
    7
    8
    - (void)forwardInvocation:(NSInvocation *)invocation
    {
    if (self.object) {
    [invocation setTarget:self.object];

    [invocation invoke];
    }
    }

准备就绪,现在要开始变身了

假设我现在有两个类,

YFPerson

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#import "YFPerson.h"

@interface YFPerson ()

@property (nonatomic,copy)NSString *name;

@end

@implementation YFPerson

- (void)eat
{
NSLog(@"%@正在吃饭",self.name);
}

@end

YFStudent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#import "YFStudent.h"

@interface YFStudent ()

@property (nonatomic,copy)NSString *studentNum;

@end

@implementation YFStudent

- (void)study
{
NSLog(@"哥正在学习");
}

@end

那么我怎么用 YFProxy“继承”这连个类呢?

  • 先初始化两个纯洁的对象

    1
    2
    YFPerson *person = [[YFPerson alloc]init];
    YFStudent *student = [[YFStudent alloc]init];
  • 为 YFProxy 开辟一块内存空间

    1
    YFProxy *proxy = [YFProxy alloc];
  • 变身

    1
    [proxy transformToObject:person];
  • 这样就可以自由自在地调用 Person 类的方法了,person 类的方法甚至是真私有的,都可以调得到,虽然报警告了

    1
    2
    3
    [proxy performSelector:@selector(setName:) withObject:@"小明"];

    [proxy performSelector:@selector(eat)];
  • 再变

    1
    [proxy transformToObject:student];
  • 这样又可以调 Student类的方法了

    1
    [proxy performSelector:@selector(study)];

是不是很神奇,当然,这只是初步的探讨,还有很多基于 OC 运行时的东西值得我们去挖掘

上面就是两种实现 OC 多继承的两种方法, 特别是第二种,我可以将 NSProxy 变成任意类,实现任意类的方法,并可以使用其属性.

叶世昌 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!
坚持原创技术分享,您的支持将鼓励我继续创作!