zoukankan      html  css  js  c++  java
  • Protocol协议分发器

    1. 用途: 能够制定多个对象实现<Protocol>, 同一个代理方法,可以在多个对象中同时实现

    2.原理: 利用消息转发机制,将方法分发到多个对象中

    使用方式:

        self.tableView.delegate = AOProtocolDispatcher(UITableViewDelegate, self, self.delegateSource);

    .h

    #import <Foundation/Foundation.h>
    
    #define AOProtocolDispatcher(__protocol__, ...)  
        [ProtocolDispatcher dispatcherProtocol:@protocol(__protocol__)  
                                toImplemertors:[NSArray arrayWithObjects:__VA_ARGS__, nil]]
    
    @interface ProtocolDispatcher : NSObject
    
    + (id)dispatcherProtocol:(Protocol *)protocol toImplemertors:(NSArray *)implemertors;
    
    @end

    .m

    
    #import "ProtocolDispatcher.h"
    #import <objc/runtime.h>
    
    struct objc_method_description MethodDescriptionForSELInProtocol(Protocol *protocol, SEL sel) {
        struct objc_method_description description = protocol_getMethodDescription(protocol, sel, YES, YES);
        if (description.types) {
            return description;
        }
        description = protocol_getMethodDescription(protocol, sel, NO, YES);
        if (description.types) {
            return description;
        }
        return (struct objc_method_description){NULL, NULL};
    }
    
    BOOL ProtocolContainSel(Protocol *protocol, SEL sel) {
        return MethodDescriptionForSELInProtocol(protocol, sel).types ? YES: NO;
    }
    
    
    @interface ImplemertorContext : NSObject
    
    @property (nonatomic, weak) id implemertor;
    
    @end
    
    @implementation ImplemertorContext
    
    @end
    
    
    @interface ProtocolDispatcher ()
    
    @property (nonatomic, strong) Protocol *prococol;
    @property (nonatomic, strong) NSArray *implemertors;
    
    @end
    
    @implementation ProtocolDispatcher
    
    + (id)dispatcherProtocol:(Protocol *)protocol toImplemertors:(NSArray *)implemertors {
        return [[ProtocolDispatcher alloc] initWithProtocol:protocol toImplemertors:implemertors];
    }
    
    - (instancetype)initWithProtocol:(Protocol *)protocol toImplemertors:(NSArray *)implemertors {
        if (self = [super init]) {
            self.prococol = protocol;
            NSMutableArray *implemertorContexts = [NSMutableArray arrayWithCapacity:implemertors.count];
            [implemertors enumerateObjectsUsingBlock:^(id implemertor, NSUInteger idx, BOOL * _Nonnull stop) {
                ImplemertorContext *implemertorContext = [ImplemertorContext new];
                implemertorContext.implemertor = implemertor;
                [implemertorContexts addObject:implemertorContext];
                objc_setAssociatedObject(implemertor, _cmd, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
            }];
            self.implemertors = implemertorContexts;
        }
        return self;
    }
    
    - (BOOL)respondsToSelector:(SEL)aSelector {
        if (!ProtocolContainSel(self.prococol, aSelector)) {
            return [super respondsToSelector:aSelector];
        }
        
        for (ImplemertorContext *implemertorContext in self.implemertors) {
            if ([implemertorContext.implemertor respondsToSelector:aSelector]) {
                return YES;
            }
        }
        return NO;
    }
    
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
        if (!ProtocolContainSel(self.prococol, aSelector)) {
            return [super methodSignatureForSelector:aSelector];
        }
        
        struct objc_method_description methodDescription = MethodDescriptionForSELInProtocol(self.prococol, aSelector);
        return [NSMethodSignature signatureWithObjCTypes:methodDescription.types];
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation {
        SEL aSelector = anInvocation.selector;
        if (!ProtocolContainSel(self.prococol, aSelector)) {
            [super forwardInvocation:anInvocation];
            return;
        }
        
        for (ImplemertorContext *implemertorContext in self.implemertors) {
            if ([implemertorContext.implemertor respondsToSelector:aSelector]) {
                [anInvocation invokeWithTarget:implemertorContext.implemertor];
            }
        }
    }
    
    @end
  • 相关阅读:
    Tomcat 跨域问题的解决
    [SheetJS] js-xlsx模块学习指南
    漂亮又好用的Redis可视化客户端汇总
    Visual Studio 2015 出现 NuGet 安装程序包错误解决方法
    vs2015使用nuget包管理器安装失败
    C# 尝试还原程序包是出错:找不到“XXXXX”版本的程序包“XXXXXX”
    基于flink和drools的实时日志处理
    Docker常用命令
    Laravel5打印所有运行SQL
    Laravel5版本在sql查询时用when方便条件判断查询【闭包方式】
  • 原文地址:https://www.cnblogs.com/daxueshan/p/11245748.html
Copyright © 2011-2022 走看看