本人有若干成套学习视频, 可试看! 可试看! 可试看, 重要的事情说三遍 包含Java
, 数据结构与算法
, iOS
, 安卓
, python
, flutter
等等, 如有需要, 联系微信tsaievan
.
OC 中一个类只有一个父类, 这就是单一继承, 但是我们可以用协议和 NSProxy 实现多继承
先说协议, 协议我们用的最多的地方,就是代理,其实代理不叫代理,叫委托, 这里就不多说了,相信大家都很熟了
那么 protocol 这个东西,是可以遵守多个的,遵守了之后,实现 protocol 中的方法,就OK 了,就是这么简单,轻松, easy
比如我有两个协议, 分别是 YFPerson,YFChild
#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
#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
- (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 对象, 然后就可以调协议中的任何方法了
- (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 方法,也就是说,它只可以开辟一块内存空间,而不能初始化. 那么,我怎么样这个类可以变成任意一个类呢?
主要有这样几步,
- 我先设置一个类 YFProxy, 继承自 NSProxy
- 为 YFProxy 设置一个 NSObject 属性
- 自定义一个转换方法,相当于给 NSObject 属性赋值
- 然后通过这个属性获得调用方法的方法签名
- 为调用设置目标
- 调用
我一步步说一遍
1.为外界暴露一个变身方法:
#import <Foundation/Foundation.h>
@interface YFProxy : NSProxy
- (id)transformToObject:(NSObject *)object;
@end
2.设置一个 NSObject 属性
#import "YFProxy.h"
@interface YFProxy ()
@property (nonatomic,strong)NSObject *object;
@end
3.实现变身方法
- (id)transformToObject:(NSObject *)object
{
self.object = object;
return self.object;
}
4.重写- (NSMethodSignature *)methodSignatureForSelector:(SEL)see
方法获得方法签名
- (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
方法改变调用对象,也就是说,让消息实际上发给真正的实现这个方法的类
- (void)forwardInvocation:(NSInvocation *)invocation
{
if (self.object) {
[invocation setTarget:self.object];
[invocation invoke];
}
}
准备就绪,现在要开始变身了
假设我现在有两个类,
YFPerson
#import "YFPerson.h"
@interface YFPerson ()
@property (nonatomic,copy)NSString *name;
@end
@implementation YFPerson
- (void)eat
{
NSLog(@"%@正在吃饭",self.name);
}
@end
YFStudent
#import "YFStudent.h"
@interface YFStudent ()
@property (nonatomic,copy)NSString *studentNum;
@end
@implementation YFStudent
- (void)study
{
NSLog(@"哥正在学习");
}
@end
那么我怎么用 YFProxy"继承"这连个类呢?
- 先初始化两个纯洁的对象
YFPerson *person = [[YFPerson alloc]init];
YFStudent *student = [[YFStudent alloc]init];
- 为 YFProxy 开辟一块内存空间
YFProxy *proxy = [YFProxy alloc];
- 变身
[proxy transformToObject:person];
- 这样就可以自由自在地调用 Person 类的方法了,person 类的方法甚至是真私有的,都可以调得到,虽然报警告了
[proxy performSelector:@selector(setName:) withObject:@"小明"];
[proxy performSelector:@selector(eat)];
- 再变
[proxy transformToObject:student];
- 这样又可以调 Student类的方法了
[proxy performSelector:@selector(study)];
是不是很神奇,当然,这只是初步的探讨,还有很多基于 OC 运行时的东西值得我们去挖掘