NSInvocation 将 C 数组传递给 Objective-C 方法

Posted

技术标签:

【中文标题】NSInvocation 将 C 数组传递给 Objective-C 方法【英文标题】:NSInvocation pass C-arrays to Objective-C method 【发布时间】:2012-01-31 00:45:31 【问题描述】:

我想在延迟后将 C 数组传递给 Objective-C 中的方法。通常我可以执行Selector:withObject:afterDelay,但我不能以任何方式更改数组或将它们转换为 NSMutableArrays、NSDictionaries 或任何其他 Cocoa 对象——它们必须是 C 数组。在我对 *** 和 Google 的研究中,我发现传递 C 原语的一种方法是将它们包装在 NSInvocation 中。我尝试使用下面的代码执行此操作,并将参数设置为指向正在传递的数组的指针。

float gun1_vertex[24][8] =  data,...data,data,...data, ... data,...data ;
float gunDown1_vertex[24][8] =  data,...data,data,...data, ... data,...data ;

NSInvocation *inv = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(testMethod:secondCArray:)]];
  [inv setSelector:@selector(testMethod:secondCArray:)];
  [inv setTarget:self];
  [inv setArgument:&gun1_vertex[0][0] atIndex:2];
  [inv setArgument:&gunDown1_vertex[0][0] atIndex:3];
  [inv performSelector:@selector(invoke) withObject:nil afterDelay:0.1f];

当我尝试在下面的方法中从传递的数组中打印一些值时,我的测试应用程序不断崩溃。我可能只是错过了一些完全明显的东西。有人可以在这里阐明一下吗?

- (void)testMethod:(float *)test secondCArray:(float *)test2 

    for ( int a = 0 ; a < 10 ; a++ ) 

        NSLog(@"%f %f",test[a],test2[a]);

    


【问题讨论】:

你能改变接受对象的方法吗?如果是这样,您可以将字节粘贴到 NSData 中,然后在另一侧解压。 @JoshCaswell:或者只是创建一个中间“thunk”方法来进行解包,然后转身并调用所需的目标方法。 不,我不能修改 C 数组。 NSInvocation 的语法看起来不错吗?看起来它应该可以工作 - 指向多维数组的第一个元素的指针,然后在传递给 testMethod 后打印出一些值。我在 NSLog 行收到了 EXC_BAD_ACCESS。 @quixoto:好主意。 phil:我们不建议修改数组,只是将它们放在一个包装器中。关于。 EXC_BAD_ACCESS:你确定调用方法时内存仍然有效吗? NSInvocation 复制你给它的指针,但它不能复制数据本身,因为它不知道有多少。 哦,也许包装它就可以了。你能告诉我你是如何在 NSData 中打包/解包它的吗?我确信数据仍然有效,因为它是从头文件导入的,并且是一个静态顶点数组。 【参考方案1】:

你可以这样做:

-(void) testMethod:(NSData *) arrayone secondArray:(NSData *) arraytwo

    float **gun1_vertex = (float **)[arrayone bytes];
    float **gunDown1_vertex = (float **)[arraytwo bytes];

    // ...


NSData *gun1data = [NSData dataWithBytes:(void *)gun1_vertex     length:sizeof(float) * 24 * 8];
NSData *gun1downData = [NSData dataWithBytes:(void *)gunDown1_vertex length:sizeof(float) * 24 * 8];

[inv setArgument:&gun1data atIndex:2];
[inv setArgument:&gun1downData atIndex:3];

【讨论】:

谢谢,这是我一直在寻找的用 NSData 包装的示例。 dataWithBytes: 构造一个NSData复制 原始数组,鉴于原始数组是静态的,这肯定是相当过分的? testMethod中的变量类型也应该是float *(C数组是矩形的,不是向量的向量...)。 @CRD 数组不是静态的,它们是在堆栈上分配的,并且会在函数退出时被销毁,在执行 testMethod 时使它们成为垃圾。因此使用了 NSData。 这是错误的! setArgument 需要一个指向实际参数的指针。这意味着,当参数是指向对象的指针 (NSData *) 时,您需要给它一个指向指针的指针 (NSData **)。 [NSData dataWithBytes:... 不是你需要通过的;你需要传递一个指向它的指针。【参考方案2】:

你的问题是没有足够的间接性。 setArgumentpointer 指向您希望设置为参数的值的位置,在您的情况下该值也是一个指针...使用传递的指针和类型信息 @987654322 @ 可以复制正确的字节数。

所以你需要这样的东西:

float *gun1_vertex_pointer = &gun1_vertex[0][0];
[inv setArgument:&gun1_vertex_pointer atIndex:2];

【讨论】:

感谢这解决了我最初的问题,即理解调用的 setArgument 部分。 我不明白。为什么要获取数组第一个元素的地址?只需发送数组本身,这只会增加复杂性。 @user102008 - 正确!鸡蛋在脸上,我对另一个答案发表了同样的评论并犯了同样的错字:-(已修复。 @RichardJ.RossIII - 抱歉错过了您的评论。到现在为止,您已经知道了答案,因为您刚刚修复了自己的响应。【参考方案3】:

要在延迟后拨打电话,请使用dispatch_after 块:

    double delayInSeconds = 0.1;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void)
        [self testMethod:&gun1_vertex[0][0] secondCArray:&gunDown1_vertex[0][0]];
    );

【讨论】:

我喜欢这个解决方案,但也许 OP 有理由改用 NSInvocation。

以上是关于NSInvocation 将 C 数组传递给 Objective-C 方法的主要内容,如果未能解决你的问题,请参考以下文章

可以将 Java 数组传递给采用数组的 C/C++ 函数吗?

在没有回调的情况下将选择器分配给Objective-C中的C函数

将多维数组传递给函数 C

将二维 C 数组传递给 python numpy

C:将数组“即时”传递给函数

为啥不允许将数组按值传递给 C 和 C++ 中的函数?