要传递给C函数的Objective-C选择器指针

要传递给C函数的Objective-C选择器指针,objective-c,c,pointers,function-pointers,Objective C,C,Pointers,Function Pointers,我有一个包含函数指针的C结构。现在,我在C中使用这个设置没有问题,但是现在我在Objective-C中使用这个C结构,我需要传递一个在Objective-C类中定义的函数(或选择器)指针 1。下面是我对Objective-C选择器的介绍,它需要作为指向C函数的指针传递: - (void)myObjCSelector:(int*)myIntArray { // Do whatever I need with myIntArray } IMP myObjCSelectorPointer

我有一个包含函数指针的C结构。现在,我在C中使用这个设置没有问题,但是现在我在Objective-C中使用这个C结构,我需要传递一个在Objective-C类中定义的函数(或选择器)指针

1。下面是我对Objective-C选择器的介绍,它需要作为指向C函数的指针传递:

- (void)myObjCSelector:(int*)myIntArray
{
    // Do whatever I need with myIntArray
}
 IMP myObjCSelectorPointer = (void (*)(id,SEL,int*))[self methodForSelector:@selector(myObjCSelector:)];
2。在Objective-C中,我试图将选择器作为指向C函数调用的指针传递:代替“myObjectorPointer”,我需要正确的语法将选择器作为C函数调用中的函数指针传递:

passObjCSelectorPointerToCContext(cContextReference, myObjCSelectorPointer);
objc_msgSend(myobject, @selector(somemethod))

我确实研究过这个问题,但主要可以找到几种不同的方法来做类似的事情,但我找不到任何调用C函数和传递Objective-C选择器指针的具体方法。

在objc中,选择器不是函数指针。选择器是映射到objc运行时存储的方法查找表中的字符串的唯一整数。在上述情况下,您的方法名称将是
myObjCSelector:
,要获取它的唯一选择器,您需要键入
@selector(myObjCSelector:)
。但是,这对您没有任何用处,因为它并不表示函数的特定实现

你要找的是小鬼。请参考这个问题

编辑2:

- (void)myObjCSelector:(int*)myIntArray
{
    // Do whatever I need with myIntArray
}
 IMP myObjCSelectorPointer = (void (*)(id,SEL,int*))[self methodForSelector:@selector(myObjCSelector:)];
然后可以使用

myObjCSelectorPointer(self,@selector(myObjCSelector:),myIntArray);
但是,这意味着您需要确保在c函数调用passObjCSelectorPointerToCContext中添加指向self的指针。 所以应该是这样的

passObjCSelectorPointerToCContext(cContextReference, self, myObjCSelectorPointer); 
从包含该方法的对象中调用时

但需要注意的是,使用IMP几乎从来都不是正确的技术。您应该尝试使用纯Obj-C。Obj-C在第一次调用消息后非常有效,因为它使用时态缓存

编辑1:

- (void)myObjCSelector:(int*)myIntArray
{
    // Do whatever I need with myIntArray
}
 IMP myObjCSelectorPointer = (void (*)(id,SEL,int*))[self methodForSelector:@selector(myObjCSelector:)];
了解objc为何以这种方式工作是很有用的。苹果公司对此进行了深入的记录。但是,简要说明如下:

当您向对象(如
[myobject somemethod]
发送消息时,编译器不会立即知道要调用somemethod的哪个特定实现,因为可能有多个类具有somemethod的多个重写版本。所有这些方法都有相同的选择器,不管它的参数和返回值如何,因此决定在程序运行时将somemethod的哪个实现与之不同<代码>[myobject somemethod]被编译器转换为C函数调用:

passObjCSelectorPointerToCContext(cContextReference, myObjCSelectorPointer);
objc_msgSend(myobject, @selector(somemethod))
这是一个特殊的函数,用于搜索每个
myobject
类布局,以查看该类是否知道如何响应
somemethod
消息。如果不是,则搜索该类的父类,依此类推,直到找到根。如果没有一个类可以响应
somemethod
,那么
NSObject
定义一个名为forward的私有方法,在该方法中发送所有未知消息

假设一个类可以响应
somemethod
消息,那么它还将有一个IMP类型的特定指针,该指针指向该方法的实际实现。此时将调用该方法

这个过程比我描述的要多得多,但是大纲应该足以帮助您理解选择器的目标是什么


最后一点是,通过
@selector
指令将方法名称映射到唯一整数的原因是,运行时不必浪费时间进行字符串比较。

基本上,答案是:Objective-C选择器不同于函数指针。您需要两段数据来执行选择器。这是一个对象和选择器本身。你需要一些胶水来完成你的任务

检查问题。

是否必须使用函数指针?在Objective-C中,您可以获得指向任意方法实现(称为
IMP
)的函数指针,但这非常少见,通常不是一个好主意。直接调用
objc\u msgSend()
也不是最好的主意,因为
objc\u msgSend()
有几种不同的变体,编译器会根据方法的返回类型自动选择不同的变体。返回对象的方法经过
objc\u msgSend()
,但返回结构的对象可能经过
objc\u msgSend()
或经过
objc\u msgSend\u stretc()
。如果该方法返回一个
double
,那么它将通过
objc\u msgSend\u fpret()

文件:

相反,我可能建议使用目标操作对,或使用块。然后你可以做一些类似的事情:

myContextRef->target = anObjcObject;
myContextRef->action = @selector(invokeMe:);
完成后,请执行以下操作:

[myContextRef->target performSelector:myContextRef->action withObject:someReturnInformation];
myContextRef->completionHandler(someReturnInformation);
或者使用块:

myContextRef->completionHandler = [^(id returnInformation) {
  [anObjcObject invokeMe:returnInformation];
} copy];
完成后,请执行以下操作:

[myContextRef->target performSelector:myContextRef->action withObject:someReturnInformation];
myContextRef->completionHandler(someReturnInformation);

(不要忘记在释放上下文时释放块)

+1因为你完全正确,但是-1因为我不认为直接使用原始
IMP
是最好的方法。直接调用objc_msgSend几乎从来都不是一个好主意。所以他们取消了;)我同意使用直接IMP几乎从来都不是最好的方法。我做了相应的更新。这是一个很好的问题,因为它突出了一个关于选择器是函数指针的常见误解,这是错误的,大多数新的objc程序员都持有这种误解。我真的很感谢我得到的所有答案,我明白学习和理解选择器和函数之间的差异是多么重要。但对于寻找同一问题的其他用户的后代和理智来说,我正在寻找一个与这个问题直接相关的简明答案。我已经看完了答案,也看完了链接