RACBlockTrampoline
RACBlockTrampoline 类是 ReactiveCocoa 框架中内部使用的类,用于调用动态的回调代码块。
+ (id)invokeBlock:(id)block withArguments:(RACTuple *)arguments {
NSCParameterAssert(block != NULL);
RACBlockTrampoline *trampoline = [[self alloc] initWithBlock:block];
return [trampoline invokeWithArguments:arguments];
}
要正常使用该方法,block 不能为空,并且其所包含的参数必须和 arguments 的分量个数保持一致,且参数是必须的,当然最多支持 15 个参数。
- (id)invokeWithArguments:(RACTuple *)arguments {
SEL selector = [self selectorForArgumentCount:arguments.count];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:selector]];
invocation.selector = selector;
invocation.target = self;
for (NSUInteger i = 0; i < arguments.count; i++) {
id arg = arguments[i];
NSInteger argIndex = (NSInteger)(i + 2);
[invocation setArgument:&arg atIndex:argIndex];
}
[invocation invoke];
__unsafe_unretained id returnVal;
[invocation getReturnValue:&returnVal];
return returnVal;
}
这个方法很简单,首先调用下面的方法,根据 arguments 所包含的分量个数确定 block 中的参数个数,从而确定后面需要调用的方法。
- (SEL)selectorForArgumentCount:(NSUInteger)count {
NSCParameterAssert(count > 0);
switch (count) {
case 0: return NULL;
case 1: return @selector(performWith:);
case 2: return @selector(performWith::);
··· //省略
case 15: return @selector(performWith:::::::::::::::);
}
NSCAssert(NO, @"The argument count is too damn high! Only blocks of up to 15 arguments are currently supported.");
return NULL
}
根据返回的 SEL 变量创建一个 NSInvocation 实例,而后绑定参数,最后调用 invoke 方法。
如果要在框架外使用该类,需要导入 RACBlockTrampoline.h 头文件。
#import "RACBlockTrampoline.h"
- (void)test {
id (^block)(id obj) = ^ id (id obj) {
NSLog(@"block is executed : %@ .",obj);
return obj;
};
id obj = [RACBlockTrampoline invokeBlock:block withArguments:RACTuplePack(@100)];
}