草庐IT

c++ - 从 c++ 到 objective-c 的回调

coder 2023-06-04 原文

我在 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(); }

这当然是不正确的。请给我一些建议,我该怎么做?

最佳答案

你有几个选择。

使用 block

您可以使用 block 来传达您的回调工作。这可能是最简单的解决方案,因为它允许您调用代码而无需将任何参数传递给回调“函数”。 block 在 C 及其所有带有 Clang 的超集中工作,Clang++ 甚至允许在 block 和 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++ 端进行一些修改以接受仿函数(或者如果更简单,则只接受 block )而不是函数指针。

由于 block 创建了闭包,它们对于这类工作非常方便。

Blocks 是 Apple 对 C、C++ 和 Objective-C 的扩展。查看更多关于他们的信息here .

使用 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 调用约定,可变参数调用约定并不总是相同)。 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++ - 从 c++ 到 objective-c 的回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12201292/

有关c++ - 从 c++ 到 objective-c 的回调的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  4. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  5. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser

  6. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  7. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  8. objective-c - 在设置 Cocoa Pods 和安装 Ruby 更新时出错 - 2

    我正在尝试为我的iOS应用程序设置cocoapods但是当我执行命令时:sudogemupdate--system我收到错误消息:当前已安装最新版本。中止。当我进入cocoapods的下一步时:sudogeminstallcocoapods我在MacOS10.8.5上遇到错误:ERROR:Errorinstallingcocoapods:cocoapods-trunkrequiresRubyversion>=2.0.0.我在MacOS10.9.4上尝试了同样的操作,但出现错误:ERROR:Couldnotfindavalidgem'cocoapods'(>=0),hereiswhy:U

  9. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  10. ruby - 你会如何在 Ruby 中表达成语 "with this object, if it exists, do this"? - 2

    在Ruby(尤其是Rails)中,您经常需要检查某物是否存在,然后对其执行操作,例如:if@objects.any?puts"Wehavetheseobjects:"@objects.each{|o|puts"hello:#{o}"end这是最短的,一切都很好,但是如果你有@objects.some_association.something.hit_database.process而不是@objects呢?我将不得不在if表达式中重复两次,如果我不知道实现细节并且方法调用很昂贵怎么办?显而易见的选择是创建一个变量,然后测试它,然后处理它,但是你必须想出一个变量名(呃),它也会在内存中

随机推荐