如何在C++;使用来自ObjC类的std::函数回调? 全局 我有一个C++库,它可以异步工作,包括网络。它有一个特定于达尔文的后端,使用GrandCentralDispatch的C API将工作委托给其他线程。现在,我想通过一层薄薄的ObjC++使用一个新的iOS应用程序编写的库
我在OSX10.10上使用Xcode 6.3.2如何在C++;使用来自ObjC类的std::函数回调? 全局 我有一个C++库,它可以异步工作,包括网络。它有一个特定于达尔文的后端,使用GrandCentralDispatch的C API将工作委托给其他线程。现在,我想通过一层薄薄的ObjC++使用一个新的iOS应用程序编写的库,ios,c++11,asynchronous,objective-c++,Ios,C++11,Asynchronous,Objective C++,我在OSX10.10上使用Xcode 6.3.2 在这个最小的示例中,我重新创建了上述体系结构。问题在于,当操作通过std::function回调返回时,启动异步操作的ObjC类实例不知何故“断开”。只有将std::函数声明为[&]而不是[=]时,才会发生这种情况。我不能使用后者,因为它不被“真实”C++代码支持。 调用ObjC++的Swift代码如下所示: class MyViewController : UIViewController { var test = Objective
在这个最小的示例中,我重新创建了上述体系结构。问题在于,当操作通过std::function回调返回时,启动异步操作的ObjC类实例不知何故“断开”。只有将std::函数声明为
[&]
而不是[=]
时,才会发生这种情况。我不能使用后者,因为它不被“真实”C++代码支持。
调用ObjC++的Swift代码如下所示:
class MyViewController : UIViewController {
var test = ObjectiveTest()
override func viewDidAppear(animated: Bool) {
test.testAsyncWork("some data", withHandler: { (result: Int32) -> Void in
println("Work result: \(result)")
})
}
}
handler WorkBlock & error: summary string parsing error 0xbffa50cc
&handler __block_literal_generic * 0x7c000000 0x0ae08500
__isa void * NULL 0x00000000
__flags int 0 0
__reserved int 2080876705 2080876705
__FuncPtr void (*)(int) 0x7c000000 0x7c000000
__descriptor __block_descriptor * 0x7c085b10 0x7c085b10
如果我注释掉代码,视图控制器将显示并保持可见,因此它不应该杀死ObjectiveTest实例。这就是ObjC++粘合层:
@interface ObjectiveTest () {
__block Test *test;
__block int _a;
}
@end
@implementation ObjectiveTest
- (id)init
{
self = [super init];
if (self) {
test = new Test();
_a = 42;
if (!test)
self = nil;
}
return self;
}
- (void)deinit
{
delete test;
}
- (void)testAsyncWork:(NSString *)someData withHandler:(WorkBlock)handler
{
_a++;
NSLog(@"_a = %i", _a); // valid
NSLog(@"handler = %@", handler); // valid
test->testAsyncWork(someData.UTF8String, [&](int result) {
_a++;
NSLog(@"result = %i", result); // Expected: "result = 666" - valid
NSLog(@"_a = %i", _a); // Expected: "_a = 44" - invalid
NSLog(@"handler = %@", handler); // invalid, crashes here
});
}
@end
P>最后,做“工作”的C++方法:
从这一点上,我得到的印象是ObjectiveTest实例在过程中的某个地方中断了,但由于它保存在MyViewController中,我不知道这是如何发生的。我可能遗漏了什么吗?
[&]
通过引用捕获变量。如果原始变量在任务完成之前过期,则捕获的引用将挂起
由于异步调用可能旨在异步完成1,因此基本上可以保证挂起引用
在进行异步调用时,您几乎总是希望按值捕获。您甚至可能希望明确列出您捕获的内容,以便了解您引入的依赖项。(如果没有隐藏/隐式依赖项,多线程代码就足够硬了)
[&]
捕获的唯一有效用途是创建一个“访问者”类型的对象,将其传递到将使用lambda的函数中,然后在它返回之前丢弃它及其所有副本。除此之外,您还应该通过价值捕获,或者非常仔细地选择您通过引用捕获的内容,并证明涵盖了生命周期问题
1可能希望
[&]
的异步方法的一个示例是“在UI泵线程上运行”异步调用,在该调用中,您希望工作线程暂停进程,直到结果从UI线程返回。在这里,您要在离开当前作用域之前,阻止返回的std::future
(或等效值)。Um,使用[&]
进行异步调用是一个非常糟糕的主意?它通过引用捕获变量,当您离开当前范围时,它通过引用捕获的变量就消失了。因此,您正在对一组无效的对象进行大量读取。。。你想干什么?确切地说,为什么你认为[=]
不起作用?要做出响应,请输入一条带有@yakk的注释。[&]
只适用于一种狭隘的情况,但这涉及到更少的异步,更多的同步。(你想在一个特定的线程上运行某个任务。所以你发送任务,然后阻塞直到任务完成,从而阻止代码前进)。@yakk,你是对的。由于某种原因,当我编写新代码时,我一直在想“<代码> [/]代码],而在C++代码中我也这样做。我确实理解其中的区别,一定是我的大脑不喜欢[=]
。。。如果你把它作为答案贴出来,我会接受的。:)此外,这里通过引用捕获没有意义,因为捕获的变量(self
和handler
)都没有分配给任何一个,所以通过值捕获是等效的和更好的。此外,您从不使用\u block
声明实例变量。这是无用的,最好是编译器错误<代码>\u块仅对局部变量有任何意义,因为这些是唯一可以“捕获”的变量。此外,捕获的引用可能应该很弱,以避免引用循环和对象泄漏的可能性。请注意,objective-C块通过const copy隐式捕获块中使用的任何内容(这会导致对已引用计数的objective-C对象进行引用)。您可能会意外地通过复制在操作间代码中捕获self
-或更糟的此
。我还建议您避免使用C++11 lambda的[&]
和[=]
捕获所有按引用/值表示法,并显式列出捕获。使用<代码> STD::VistuxPTR 将C++对象传递给块。
handler WorkBlock & error: summary string parsing error 0xbffa50cc
&handler __block_literal_generic * 0x7c000000 0x0ae08500
__isa void * NULL 0x00000000
__flags int 0 0
__reserved int 2080876705 2080876705
__FuncPtr void (*)(int) 0x7c000000 0x7c000000
__descriptor __block_descriptor * 0x7c085b10 0x7c085b10