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】:
你的问题是没有足够的间接性。 setArgument
将 pointer 指向您希望设置为参数的值的位置,在您的情况下该值也是一个指针...使用传递的指针和类型信息 @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++ 函数吗?