美文网首页Objective-CiOS 开发tom
协议和 NSProxy 实现多继承

协议和 NSProxy 实现多继承

作者: 小冰山口 | 来源:发表于2016-10-21 01:04 被阅读416次

    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 运行时的东西值得我们去挖掘

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

    相关文章

      网友评论

      本文标题:协议和 NSProxy 实现多继承

      本文链接:https://www.haomeiwen.com/subject/gfqfuttx.html