美文网首页
Runtime(四)模拟多继承的实现

Runtime(四)模拟多继承的实现

作者: 炒河粉儿 | 来源:发表于2019-08-16 10:37 被阅读0次

    思想

    iOS中是不允许多继承的,一个类既可以同时实现其他两个类的方法。一般有两种方式,一种是将这两个类的对象作为参数传入去调用各自的方法,另一种是通过代理协议的方式实现。但追其根本还是通过这两个类进行的方法调用。
    我们可以利用runtime,模拟实现多继承的效果,通过消息转发机制中的第三步,方法签名和消息转发可以实现当前类调用方法,转发到对应的实现的类中去实现。

    代码

    定义两个类,各自声明实现各自的方法。通过协议的方式去声明方法。

    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @protocol FruitsProviderProtocol
    
    - (void)buyFruits:(NSString *)fruits;
    
    @end
    
    @interface FruitsProvider : NSObject
    
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "FruitsProvider.h"
    
    @interface FruitsProvider() <FruitsProviderProtocol>
    
    @end
    
    @implementation FruitsProvider
    
    - (void)buyFruits:(NSString *)fruits
    {
        NSLog(@"fruits: %@",fruits);
    }
    
    
    #import <Foundation/Foundation.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @protocol RestaurantProviderProtocol
    
    - (void)order:(NSString *)orderName;
    
    @end
    
    @interface RestaurantProvider : NSObject
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    #import "RestaurantProvider.h"
    
    @interface RestaurantProvider() <RestaurantProviderProtocol>
    
    @end
    
    @implementation RestaurantProvider
    
    - (void)order:(NSString *)orderName
    {
        NSLog(@"order: %@",orderName);
    }
    
    @end
    
    

    定义一个类,通过遵守协议的方式,将另外两个类的方法引入。

    #import <Foundation/Foundation.h>
    #import "FruitsProvider.h"
    #import "RestaurantProvider.h"
    
    NS_ASSUME_NONNULL_BEGIN
    
    // NSProxy
    //抽象的类,虚类,NSProxy没有构造方法,自己去提供构造方法,并且复写方法签名和消息转发两个方法。
    @interface TakeOutProxy : NSProxy <FruitsProviderProtocol,RestaurantProviderProtocol>
    
    - (instancetype)init;
    
    @end
    
    NS_ASSUME_NONNULL_END
    

    自定义构造方法,重写init方法,先将两外两个类的方法列表获取到,保存在一个字典中。当外部通过这个类调用方法的时候,由于该类中没有实现这个方法,因此会走消息转发的流程,对当前调用的方法重新签名,通过方法名找到对应实现这个方法的类,将这个消息转发给这个类的对象。从而实现方法的调用。

    #import "TakeOutProxy.h"
    #import <objc/runtime.h>
    
    @interface TakeOutProxy()
    
    {
        NSMutableDictionary *_methodDict;
    }
    
    @end
    
    @implementation TakeOutProxy
    
    //多继承 继承两个类的方法和实现
    //解决方法1:通过把这两个类的对象传进来,通过这两个类分别调用两个方法实现。
    //解决方法2:通过协议的方式实现。
    //这两个方法本质上都是原来的类去实现的这个方法。
    //复写方法签名和消息转发两个方法
    
    //通过协议的方式
    
    + (instancetype)takeOutProxy
    {
        return [[TakeOutProxy alloc]init];
    }
    
    
    - (instancetype)init
    {
        _methodDict = [NSMutableDictionary dictionary];
        
        [self registerMethodTarget:[FruitsProvider new]];
        
        [self registerMethodTarget:[RestaurantProvider new]];
        
        return self;
    }
    
    //将两个类的方法遍历,存放在一个字典中
    - (void)registerMethodTarget:(id)target {
        
        unsigned int count = 0;
        
        //runtime 获取方法列表
        Method *method_list = class_copyMethodList([target class], &count);
        
        for (int i = 0; i<count; i++) {
            Method *method = method_list[i];
            SEL *sel = method_getName(method);
            [_methodDict setObject:target forKey:NSStringFromSelector(sel)];
        }
        
        
        //记得释放
        free(method_list);
        
    }
    
    - (nullable NSMethodSignature *)methodSignatureForSelector:(SEL)sel
    {
        NSString *methodName = NSStringFromSelector(sel);
        
        id target = _methodDict[methodName];
        
        if (target && [target respondsToSelector:sel]) {
            return [target methodSignatureForSelector:sel];
        }else {
            return [super methodSignatureForSelector:sel];
        }
        
    }
    
    - (void)forwardInvocation:(NSInvocation *)invocation
    {
        SEL sel = [invocation selector];
        NSString *methodName = NSStringFromSelector(sel);
        id target = _methodDict[methodName];
        if (target && [target respondsToSelector:sel]) {
            [invocation invokeWithTarget:target];
        }else {
            [super forwardInvocation:invocation];
        }
    }
    
    
    @end
    

    相关文章

      网友评论

          本文标题:Runtime(四)模拟多继承的实现

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