从通用方法接收参数

Oss*_*sir 4 reflection objective-c variadic-functions ios

我正在尝试从我的类调用的一些随机方法接收运行时的参数.在arm64(on armv7armv7s)之前可以使用以下代码完成:

@interface MyClass
// It does not matter what method, we declare it for compiler only
- (id)methodWithFirstParameter:(id)firstParam secondParameter:(id)secondParam;
@end

@implementation MyClass

+ (BOOL)resolveInstanceMethod:(SEL)sel {
    [self addDynamicCallForSelector:sel];
    return YES;
}

+ (void)addDynamicCallForSelector:(const SEL)selector {
    const char *encoding;
    IMP implementation;
    implementation = [self instanceMethodForSelector:@selector(dynamicMethod:)];
    Method newMethod = class_getInstanceMethod([self class], @selector(dynamicMethod:));
    encoding = method_getTypeEncoding(newMethod);
    class_addMethod([self class], selector, implementation, encoding);
}

- (id)dynamicMethod:(id)obj1, ... {
    int parameterCount = [[NSStringFromSelector(_cmd) componentsSeparatedByString:@":"] count] - 1;
    NSMutableArray *parameterList = [[NSMutableArray alloc] initWithCapacity:parameterCount];
    va_list arguments;
    va_start(arguments, obj1);
    for (int i = 0; i < parameterCount; i++) {
        id parameter = (i == 0) ? obj1 : va_arg(arguments, id);
        if (!parameter) {
            parameter = [NSNull null];
        }
        [parameterList addObject:parameter];
    }
    va_end(arguments);
    return parameterList;
}
Run Code Online (Sandbox Code Playgroud)

这很简单干净.我们只是将所有传入调用传递给一个可以从中收集参数并返回它们的实现.

arm64但是,va_list工作不错,但在这样的背景下,从第一个参数va_arg(arguments, id)是类的当前实例(self).第二次通话后,它停止了EXC_BAD_ACCESS.所以我认为它甚至没有找到第一个参数(带va_start(arguments, obj1)).

另请注意,arm64如果我dynamicMethod:直接调用(并手动设置参数数量),va_list功能可以正常工作.我猜测它由于错误的方法编码而无效(它不会arm64像以前那样神奇地将一个方法转换为另一个具有不同数量的参数的方法).

您可以在这里查看所有代码,它基本上是此解决方案的 Web服务的一部分.

Tom*_*ift 7

您的代码失败的原因很可能是因为arm(32位)和arm64之间的调用约定不同.也就是说,关于如何将参数传递给函数以及如何返回值,将应用不同的规则.

之前没有"魔术转换".你很幸运,可变函数的调用约定与非可变函数的调用约定相同 - 至少在你的用例中是这样.

请参阅ARM64 过程调用标准ARM过程调用标准(非64位)中的参数传递部分.

祝你好运解决这个问题 您可能必须有两个单独的代码路径.

编辑

我相信实现你所追求的目标的"正确"方法是使用你希望处理的所有可能的参数排列来实现许多函数,并根据选择器签名动态地解决这些问题. JSCocoa这是否使用的是什么,他们称之为"伯克斯池"(我相信命名为蒂姆·伯克斯)

另请查看适用于iOS的libffi:https: //github.com/roupam/Objective-C-NuREPL-for-iOS/tree/master/Remote/libffi

最后,一个相关的帖子: - 带有double值的[NSInvocation getReturnValue:]意外地产生0