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

猜你喜欢

转载自www.cnblogs.com/daxueshan/p/11245748.html