Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/105.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 从泛型方法接收参数_Ios_Objective C_Reflection_Variadic Functions - Fatal编程技术网

Ios 从泛型方法接收参数

Ios 从泛型方法接收参数,ios,objective-c,reflection,variadic-functions,Ios,Objective C,Reflection,Variadic Functions,我试图在运行时从类上调用的某个随机方法接收参数。在arm64(在armv7和armv7s上)之前,可以使用以下代码执行此操作: @interface MyClass // It does not matter what method, we declare it for compiler only - (id)methodWithFirstParameter:(id)firstParam secondParameter:(id)secondParam; @end @implementation

我试图在运行时从类上调用的某个随机方法接收参数。在
arm64
(在
armv7
armv7s
上)之前,可以使用以下代码执行此操作:

@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;
}
@接口MyClass
//不管是什么方法,我们只为编译器声明它
-(id)methodWithFirstParameter:(id)firstParam secondParam:(id)secondParam;
@结束
@MyClass的实现
+(BOOL)resolveInstanceMethod:(SEL)SEL{
[self-addDynamicCallForSelector:sel];
返回YES;
}
+(void)addDynamicCallForSelector:(const SEL)选择器{
常量字符*编码;
IMP实施;
实现=[selector:@selector的自实例化方法(dynamicMethod:)];
方法newMethod=class_getInstanceMethod([self class],@selector(dynamicMethod:);
编码=方法\u getTypeEncoding(newMethod);
类\添加方法([自类]、选择器、实现、编码);
}
-(id)动态方法:(id)obj1。。。{
int参数count=[[NSStringFromSelector(_cmd)组件由字符串分隔:@:“]count]-1;
NSMutableArray*参数列表=[[NSMutableArray alloc]initWithCapacity:parameterCount];
va_列表参数;
va_开始(参数,obj1);
对于(int i=0;i
这很简单,也很干净。我们只是将所有传入调用传递给一个实现,该实现可以从中收集参数并返回它们

然而,在
arm64
中,
va_list
运行良好,但是在这种情况下,
va_arg(参数,id)
中的第一个参数是类的当前实例(
self
)。在第二次呼叫后,它将通过
EXC\u BAD\u访问停止。所以我认为它甚至没有找到第一个参数(使用
va_start(arguments,obj1)

另外请注意,如果我直接调用
dynamicMethod:
(并手动设置参数的数量),那么va_list功能在
arm64
上运行良好。我胡乱猜测,它之所以不起作用,是因为方法编码错误(它不会像以前一样,在
arm64
上神奇地将一个方法转换为另一个具有不同数量参数的方法)


您可以查看所有代码,它基本上是web服务的一部分。

A找到了另一种动态调用函数的方法。看看这段代码:

- (void)requestSucceeded 
{
    NSLog(@"requestSucceeded");
    id owner = [fbDelegate class];
    SEL selector = NSSelectorFromString(@"OnFBSuccess");
    NSMethodSignature *sig = [owner instanceMethodSignatureForSelector:selector];
    _callback = [NSInvocation invocationWithMethodSignature:sig];
    [_callback setTarget:owner];
    [_callback setSelector:selector];
    [_callback retain];       // <------ See the partial doc attached

    [_callback invokeWithTarget:fbDelegate];
}
-(void)请求成功
{
NSLog(@“requestsuccessed”);
id所有者=[fbDelegate类];
SEL selector=NSSelectorFromString(@“OnFBSuccess”);
NSMethodSignature*sig=[所有者实例方法签名选择器:选择器];
_回调=[NSInvocation invocationWithMethodSignature:sig];
[_callbacksettarget:owner];
[_回调设置选择器:选择器];

[_callbackretain];//代码失败的原因可能是因为arm(32位)和arm64之间的调用约定不同。也就是说,在如何将参数传递给函数以及如何返回值方面应用了不同的规则

以前没有“神奇的转换”,幸运的是,可变函数的调用约定与非可变函数的调用约定相同——至少在您的用例中是这样

请参阅和(非64位)中的参数传递部分

祝您解决这个问题好运;您可能需要有两个独立的代码路径

编辑

我相信实现您所追求的目标的“正确”方法是使用您希望处理的参数的所有可能排列来实现许多函数,并根据选择器签名动态地解析这些函数。这是否使用了他们所称的a(我相信命名为)

还可以查看iOS版的libffi:


最后,一篇相关帖子:

出乎意料的是,我从公关部得到了一个不错的解决方案,所以所有学分都归我所有。以下是解决方案:

- (void)forwardInvocation:(NSInvocation *)inv {
    NSUInteger n = [[inv methodSignature] numberOfArguments];

    NSMutableArray *parameterList = [[NSMutableArray alloc] init];
    for (NSUInteger i = 0; i < n - 2; i++) {
        id __unsafe_unretained arg;
        [inv getArgument:&arg atIndex:(int)(i + 2)];
        if (!arg) {
            arg = [NSNull null];
        }
        [parameterList addObject:arg];
    }
    [self dynamicWebServiceCallWithArguments:parameterList forInvocation:inv];
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSUInteger numArgs = [[NSStringFromSelector(aSelector) componentsSeparatedByString:@":"] count] - 1;
    return [NSMethodSignature signatureWithObjCTypes:[[@"@@:@" stringByPaddingToLength:numArgs + 3 withString:@"@" startingAtIndex:0] UTF8String]];
}

- (void)dynamicWebServiceCallWithArguments:(NSMutableArray *)parameterList forInvocation:(NSInvocation *)invocation {
   ... 
   id result = [self executeDynamicInstanceMethodForSelector:invocation.selector parameters:parameterList prepareToLoadBlock:prepareToLoadBlock success:successBlock failure:failureBlock];
   [invocation setReturnValue:&result];
}
-(void)转发调用:(NSInvocation*)inv{
NSU整数n=[[inv methodSignature]numberOfArguments];
NSMUTABLEARRY*参数列表=[[NSMUTABLEARRY alloc]init];
对于(整数i=0;i

如此简单,仍然如此强大。适用于任何处理器体系结构,因为它是高级解决方案。我责怪自己,我自己没有找到它=)

无望,我不知道如何使用此代码(我也查看了链接答案)。主要原因是,我现在无法更改最终用户的工作方式。我只能更改
resolveInstanceMethod:
方法的功能。此方法应将适当的方法附加到类中,以收集所有调用的参数和选择器。如果您没有得到任何信息,请随时提出任何问题。还可以查看web服务在README.md中的ice调用片段,从问题中的链接,它应该可以帮助您理解