注意:这个问题的开头与这个问题相似(第一部分相同):LINK
但是,最后一个问题完全不同。
我正在实现一个“代码注入器类”,通过方法调配可以让你有可能做这样的事情:
FLCodeInjector *injector = [FLCodeInjector injectorForClass:[self class]];
[injector injectCodeBeforeSelector:@selector(aSelector:) code:^{
NSLog(@"This code should be injected");
}];
aSelector
可以是具有可变数量的参数和可变返回类型的方法。参数 / 和返回类型可以是对象或原始类型。
首先,我附上代码,injectCodeBeforeSelector:
让您了解我在做什么(我删除了代码中不感兴趣的部分):
- (void)injectCodeBeforeSelector:(SEL)method code:(void (^)())completionBlock
{
NSString *selector = NSStringFromSelector(method);
[self.dictionaryOfBlocks setObject:completionBlock forKey:selector];
NSString *swizzleSelector = [NSString stringWithFormat:@"SWZ%@", selector];
//NSMethodSignature *signature = [self.mainClass instanceMethodSignatureForSelector:method];
// add a new method to the swizzled class
Method origMethod = class_getInstanceMethod(self.mainClass, NSSelectorFromString(selector));
const char *encoding = method_getTypeEncoding(origMethod);
[self addSelector:NSSelectorFromString(swizzleSelector) toClass:self.mainClass originalSelector:method methodTypeEncoding:encoding];
SwizzleMe(self.mainClass, NSSelectorFromString(selector), NSSelectorFromString(swizzleSelector));
}
-(void)addSelector:(SEL)selector toClass:(Class)aClass originalSelector:(SEL)originalSel methodTypeEncoding:(const char *)encoding
{
//NSMethodSignature *signature = [aClass methodSignatureForSelector:originalSel];
NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:encoding];
const char *type = [signature methodReturnType];
IMP implementation = (IMP)intGenericFunction;
if (strcmp(@encode(id), type) == 0) {
// the argument is an object
implementation = objectGenericFunction;
}
else if (strcmp(@encode(int), type) == 0)
{
// the argument is an int
implementation = (IMP)intGenericFunction;
}
else if (strcmp(@encode(long), type) == 0)
{
// the argument is a long
implementation = (IMP)longGenericFunction;
}
else if (strcmp(@encode(double), type) == 0)
{
// the argument is double
implementation = (IMP)doubleGenericFunction;
}
else if (strcmp(@encode(float), type) == 0)
{
// the argument is float
implementation = (IMP)floatGenericFunction;
}
else
{
// the argument is char or others
implementation = (IMP)intGenericFunction;
}
class_addMethod(aClass,
selector,
implementation, encoding);
}
这里发生了什么?基本上,基于原始选择器的预期返回类型,我向具有正确返回类型的对象添加一个新方法,然后应用 swizzle。
一切正常,但我想知道是否可以“压缩”以下代码(一些我不知道的语法或我缺少的东西),因为对于每个返回类型,我都有一个函数是几乎与其他相同,只有返回的类型不同。我附上其中两个作为示例:
int intGenericFunction(id self, SEL cmd, ...) {
FLCodeInjector *injector = [FLCodeInjector injectorForClass:[self class]];
[injector executeBlockForSelector:cmd];
va_list arguments, copiedArguments;
va_start ( arguments, cmd );
va_copy(copiedArguments, arguments);
va_end(arguments);
void * returnValue = getReturnValue(self, cmd, copiedArguments);
int returnedInt = *(int *)returnValue;
return returnedInt;
}
double doubleGenericFunction(id self, SEL cmd, ...) {
FLCodeInjector *injector = [FLCodeInjector injectorForClass:[self class]];
[injector executeBlockForSelector:cmd];
va_list arguments, copiedArguments;
va_start ( arguments, cmd );
va_copy(copiedArguments, arguments);
va_end(arguments);
void * returnValue = getReturnValue(self, cmd, copiedArguments);
double returnedDouble = *(double *)returnValue;
return returnedDouble;
}
如您所见,函数几乎相同,唯一不同的是返回前的 CAST 和函数的返回类型。
我正在以正确的方式实施它,还是有更有效的方式来做到这一点?谢谢