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