Files

104 lines
3.3 KiB
Objective-C

//
// WZProtocolInterceptor.m
//
// Created by WeZZard on 10/13/13.
// Copyright © 2013 WeZZard. All rights reserved.
// http://stackoverflow.com/a/18777565/3938401
#import "WZProtocolInterceptor.h"
#import <objc/runtime.h>
static inline BOOL selector_belongsToProtocol(SEL selector, Protocol * protocol);
@implementation WZProtocolInterceptor
- (id)forwardingTargetForSelector:(SEL)aSelector {
if (self.middleMan && [self.middleMan respondsToSelector:aSelector] &&
[self isSelectorContainedInInterceptedProtocols:aSelector]) {
return self.middleMan;
}
if ([self.receiver respondsToSelector:aSelector]) {
return self.receiver;
}
return [super forwardingTargetForSelector:aSelector];
}
- (BOOL)respondsToSelector:(SEL)aSelector {
if (self.middleMan && [self.middleMan respondsToSelector:aSelector] &&
[self isSelectorContainedInInterceptedProtocols:aSelector]) {
return YES;
}
if (self.receiver && [self.receiver respondsToSelector:aSelector]) {
return YES;
}
return [super respondsToSelector:aSelector];
}
- (instancetype)initWithInterceptedProtocol:(Protocol *)interceptedProtocol {
self = [super init];
if (self) {
_interceptedProtocols = @[interceptedProtocol];
}
return self;
}
- (instancetype)initWithInterceptedProtocols:(Protocol *)firstInterceptedProtocol, ...; {
self = [super init];
if (self) {
NSMutableArray * mutableProtocols = [NSMutableArray array];
Protocol * eachInterceptedProtocol;
va_list argumentList;
if (firstInterceptedProtocol) {
[mutableProtocols addObject:firstInterceptedProtocol];
va_start(argumentList, firstInterceptedProtocol);
while ((eachInterceptedProtocol = va_arg(argumentList, id))) {
[mutableProtocols addObject:eachInterceptedProtocol];
}
va_end(argumentList);
}
_interceptedProtocols = [mutableProtocols copy];
}
return self;
}
- (instancetype)initWithArrayOfInterceptedProtocols:(NSArray *)arrayOfInterceptedProtocols {
self = [super init];
if (self) {
_interceptedProtocols = [arrayOfInterceptedProtocols copy];
}
return self;
}
- (void)dealloc {
_interceptedProtocols = nil;
}
- (BOOL)isSelectorContainedInInterceptedProtocols:(SEL)aSelector{
__block BOOL isSelectorContainedInInterceptedProtocols = NO;
[self.interceptedProtocols enumerateObjectsUsingBlock:^(Protocol * protocol, NSUInteger idx, BOOL *stop) {
isSelectorContainedInInterceptedProtocols = selector_belongsToProtocol(aSelector, protocol);
* stop = isSelectorContainedInInterceptedProtocols;
}];
return isSelectorContainedInInterceptedProtocols;
}
@end
BOOL selector_belongsToProtocol(SEL selector, Protocol * protocol) {
// Reference: https://gist.github.com/numist/3838169
for (int optionbits = 0; optionbits < (1 << 2); optionbits++) {
BOOL required = optionbits & 1;
BOOL instance = !(optionbits & (1 << 1));
struct objc_method_description hasMethod = protocol_getMethodDescription(protocol, selector, required, instance);
if (hasMethod.name || hasMethod.types) {
return YES;
}
}
return NO;
}