2

我正在将 C++ 库桥接到 iPhone 应用程序。这工作正常。现在,我正在为从 C++ 库(以 lambda 调用的形式)触发的某个事件添加一个侦听器,并且必须以某种方式冒泡到 iPhone 应用程序。

我考虑过使用积木。当我实现监听器时,它看起来像这样:

typedef void (^LISTENER)( NSString* param1, NSString* param2) ;

-(void) setListener:(LISTENER) listener
{
    cppDelegate->setListener([&listener](string p1, string p2)
       {
           @autoreleasepool {
               NSString *param1 = [NSString stringWithUTF8String:p1.c_str()];
               NSString *param2 = [NSString stringWithUTF8String:p2.c_str()];
               listener(param1, param2); //This fails
           }
       }
    );
}

这就是我设置监听器的方式:

listener = ^(NSString* param1, NSString* param2) //this is a MyObj member variable
{
    @autoreleasepool {
        NSLog(@"%@, %@", param1, param2);
    }
};

[myObj setLogFunction:listener];

我看到的问题是对块侦听器的调用因listener(param1, param2);EXC_BAD_ACCESS 而失败。当我进入这一行时使用调试器,它会转到一些机器代码并失败。

我不确定发生了什么事。就好像监听器没有初始化一样。我能想到的只是块侦听器不能传递给 C++ lambda,但我不知道如何解决这个问题。我改为传递一个 void 指针并将其转换回来,但这没有任何区别。

4

2 回答 2

2

该问题与块无关,而是因为您listener通过引用(&)在 lambda 中捕获。在 C++ 中,在局部变量的作用域(调用-setListener)之后使用对局部变量的引用是未定义的行为。无论如何都没有必要通过引用来捕获它,因为您从未分配给listener变量。

解决方案是通过值来捕获它([listener](...)。

于 2013-09-30T22:41:37.013 回答
0

块文字是在堆栈上创建的,如果它们的使用方式比创建它们的上下文寿命长,则必须复制它们。在大多数情况下,当您在 Objective-c 中使用块而不是在 c++ 中时,这会自动为您完成。在我的代码中,我通常通过在传递到 c++ 之前在 Objective-c 端执行此操作来处理这个问题[listener copy],尽管在这种情况下,我认为您可能能够仅通过值而不是通过 lambda 中的引用来捕获侦听器:只需更改[&listener][listener].

于 2013-09-27T18:40:34.480 回答