从c ++回调到目标c [英] callback from c++ to objective c

查看:239
本文介绍了从c ++回调到目标c的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有ViewController在objective-c,我的大部分代码是c ++(.mm)。我想从obj-c(在c ++中)设置一些回调成员函数,并从c ++调用它们。类似这样的东西(非常简化):

I have ViewController in objective-c and most of my code is c++ (.mm). I'd like to setup some callbacks to member functions from obj-c (in c++) and call them from c++. Something like this (it's very simplifyed):

@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 ++甚至允许块和Lambdas之间的隐式转换。

You may use blocks to convey your callback work. This is probably the simplest solution as it allows you to call your code without having to pass any parameter to the callback "function". Blocks work in C and all its supersets with Clang, and Clang++ even allows implicit casts between blocks and lambdas.

#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 ++端进行一些修改以接受函子

That might require some reworking on the C++ end to accept functors (or just blocks if it's simpler) instead of function pointers.

因为块创建闭包,所以对于这种工作非常方便。

Since blocks create closures, they're very convenient for that kind of works.

Blocks是Apple对C,C ++和Objective-C的扩展。有关详情,请此处

Blocks are an Apple extension to C, C++ and Objective-C. See more about them here.

使用Objective-C运行时访问选择器的函数指针。这是更繁琐的,需要你跟踪三个变量(对象调用的方法,选择器使用和方法实现),但它实际上是工作,即使在你不能使用Objective-C语法。

Use the Objective-C runtime to access the function pointer of your selector. This is more tedious and requires you to keep track of three variables (the object to call the method on, the selector to use, and the method implementation), but it actually works even in the case you can't use the Objective-C syntax.

Objective-C方法实现是具有此签名的函数指针:

Objective-C method implementations are function pointers with this signature:

typedef void (*IMP)(id self, SEL _cmd, ...);

其中 self _cmd 是导致此方法调用的选择器( _cmd 变量实际上在所有Objective-C方法中可用,尝试它),其余被认为是可变的。您需要 IMP 变量投放到正确的函数签名中,因为变量C函数的调用约定不总是与Objective- C方法调用(Objective-C方法调用是您的编译器的标准函数调用约定,可能是 cdecl 或amd64调用约定,可变调用约定是不一定相同)。

Where self is what you'd expect, _cmd is the selector that caused this method call (the _cmd variable is actually available in all Objective-C methods, try it), and the rest is considered variadic. You need to cast IMP variables into the proper function signature because the calling convention for variadic C functions doesn't always match the calling convention for Objective-C method calls (the Objective-C method call is the standard function calling convention for your compiler, probably either cdecl or the amd64 calling convention, and the variadic calling convention is not always the same). A reinterpret_cast will be able to do it.

这里有一些代码我放在一起为类似的意图。它使用C ++ 11可变参数模板来帮助获得正确的函数签名。

Here's some code I put together for similar intents. It uses C++11 variadic templates to help with getting the proper function signature.

#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运行时处理。

Also take care that your instance is not nil before using the function call, because nil checking is handled by the Objective-C runtime. In this case, we're bypassing it.

使用 - [NSObject performSelector:] 执行回调。基本上是更简单的Objective-C运行时解决方案。

Use -[NSObject performSelector:] to perform your callback. Basically a simpler version of the Objective-C runtime solution.

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 解决方案类似,您需要单独跟踪要调用的函数和要调用的对象。

Wrapping your call inside a C++ function

I think this one doesn't really need any example. Create a function that accepts your object type as the first parameter and call the method you want on it. Similarly to the SEL solution, you then need to separately keep track of the function to call and the object on which to call it.

这篇关于从c ++回调到目标c的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆