从c++到目标c的回调
callback from c++ to objective c
我在objective-c中有ViewController,我的大部分代码是c++(.mm)。我想从obj-c(在c++中)设置一些对成员函数的回调,并从c++调用它们。类似这样的东西(非常简单):
@interface MyClass
{ }
-(void)my_callback;
@end
@implementation MyClass
-(void)my_callback
{
printf("called!n");
}
-(void)viewDidLoad
{
// setup_callback( "to my_callback ?" );
}
@end
和:
void setup_callback(void(*func)()) { func(); }
这当然是不对的。有什么建议我该怎么做吗?
您有几个选项。
使用块
您可以使用块来传达您的回调工作。这可能是最简单的解决方案,因为它允许您在不必向回调"函数"传递任何参数的情况下调用代码。块在C及其所有带有Clang的超集中工作,Clang++甚至允许在块和lambda之间进行隐式类型转换。
#include <dispatch/dispatch.h>
void setup_callback(dispatch_block_t block)
{
// required to copy the block to the heap, otherwise it's on the stack
dispatch_block_t copy = [block copy];
// setup stuff here
// when you want to call the callback, do as if it was a function pointer:
// block();
}
int main()
{
MyClass* instance = [[MyClass alloc] init];
setup_callback(^{
[instance callback_method];
});
}
这可能需要对C++端进行一些重新设计,以接受函子(或者如果更简单的话,只接受块)而不是函数指针。
由于块可以创建闭包,所以它们对于这类工作非常方便。
Blocks是Apple对C、C++和Objective-C的扩展。点击此处查看更多关于他们的信息。
使用Objective-C运行时获取指向要调用的方法的函数指针
使用Objective-C运行时访问选择器的函数指针。这更为繁琐,需要跟踪三个变量(要调用方法的对象、要使用的选择器和方法实现),但即使在不能使用Objective-C语法的情况下,它也能正常工作。
Objective-C方法实现是具有以下签名的函数指针:
typedef void (*IMP)(id self, SEL _cmd, ...);
其中self
是您所期望的,_cmd
是导致此方法调用的选择器(_cmd
变量实际上在所有Objective-C方法中都可用,请尝试),其余变量则被视为可变变量。您需要将IMP
变量强制转换为正确的函数签名,因为变量C函数的调用约定并不总是与Objective-C方法调用的调用约定匹配(Objective-C方法调用是编译器的标准函数调用约定,可能是cdecl
或amd64调用约定,而variadic调用约定并不总是相同)。reinterpret_cast
将能够做到这一点。
以下是我为类似目的编写的一些代码。它使用C++11可变模板来帮助获得正确的函数签名。
#include <objc/runtime.h>
template<typename TReturnType, typename... TArguments>
auto GetInstanceMethodPointer(Class class, SEL selector) -> TReturnType (*)(id, SEL, TArguments...)
{
Method m = class_getInstanceMethod(class, selector);
IMP imp = method_getImplementation(m);
return reinterpret_cast<TReturnType (*)(id, SEL, TArguments...)>(imp);
}
int main()
{
MyClass* instance = [[MyClass alloc] init];
auto foo = GetInstanceMethodPointer<void>(
[MyClass class],
@selector(my_callback));
// foo is a void (*)(id, SEL) function pointer
foo(instance, @selector(my_callback));
}
在使用函数调用之前,还要注意您的实例不是nil
,因为nil
检查是由Objective-C运行时处理的。在这种情况下,我们绕过它。
跟踪对象和SEL
使用-[NSObject performSelector:]
执行回调。基本上是Objective-C运行时解决方案的一个更简单的版本。
void setup_callback(id object, SEL selector)
{
// do stuff
// to execute the callback:
// [object performSelector:selector];
}
int main()
{
MyClass* instance = [[MyClass alloc] init];
setup_callback(instance, @selector(my_callback));
}
将调用封装在C++函数中
我认为这个并不需要任何例子。创建一个接受对象类型作为第一个参数的函数,并调用所需的方法。与SEL
解决方案类似,您需要分别跟踪要调用的函数和要调用它的对象。
因为C++和Obj-C都是C的超集,所以可以将C++代码回调到C函数。要将回调传递回您的Obj-C对象,只需确保C回调参数包含一个指向原始Obj-C对象的指针。
// C++ calls this C function
void exampleCallback(void* classInstance)
{
// callback arguments include a pointer to the Obj-C object
[((MYObjCClassType*)classInstance) exampleCallback];
}
我认为这是不可能的:在C++代码中调用Objective-C回调。反过来也是可能的。
当我遇到这个问题时,我所做的是编写一个在Objective-C中永远运行的EVENT_LOOP,并从C++std::vector
实例中获取事件。这样,在C++中,如果您想在Objective-C中"调用"回调,只需将事件添加到相应的std::vector
中。
您可以在.mm文件中自由混合Obj-C和C++,这被称为"Objective-C++"。
为了保持C++代码和Objective-C代码的隔离,您可以在它们之间创建一个轻量级的facade,从C++回调中(以通常的方式)调用Objective-C方法。
- 架构决策:返回std::future还是提供回调
- 正在为Xtensa simcall函数编写回调函数
- 如何在C++中使用非静态成员函数作为回调函数
- FLTK:按下哪个按钮 - 将数字传递给按钮的回调 (lambda)
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- 用于在回调中调用解析器的设计模式
- 如何使用C++对象的成员函数作为 C 样式回调?
- Java从C++回调到C++回调
- 如何将成员函数作为回调参数传递给需要"typedef-ed"自由函数指针的函数?
- 从不同的 cpp 调用回调函数会导致bad_function_call
- pcap_handler回调仅在使用 NPCAP v0.9991 时包含空数据包
- 不带轮询的 SDL2 事件回调
- C++存储带有可变参数的回调
- 如何使用 Node-addon-API 实现 node-nan 回调
- 处理影响跨不同线程共享对象的定时回调的最佳方法是什么?
- 访问类C++ C 样式回调
- 处理类内的回调时,必须调用对非静态成员函数的引用
- 在窗口执行目标 TLS 回调之前注入 dll
- 从c++到目标c的回调
- 从c++向目标c调用回调函数