Objective c 按块包装c回调(桥接和块)

Objective c 按块包装c回调(桥接和块),objective-c,ios5,automatic-ref-counting,objective-c-blocks,Objective C,Ios5,Automatic Ref Counting,Objective C Blocks,我正在为标准的C API编写一个Obj-C包装器。我想用块替换C回调 让我们想象一个C API: void my_async_function(void (* callback)(void *), void *udata); Obj-C包装器如下所示: - (void)myAsyncFunction:(dispatch_block_t)block { void *udata = (__bridge_retained void *)block; my_async_function

我正在为标准的C API编写一个Obj-C包装器。我想用块替换C回调

让我们想象一个C API:

void my_async_function(void (* callback)(void *), void *udata);
Obj-C包装器如下所示:

- (void)myAsyncFunction:(dispatch_block_t)block
{
    void *udata = (__bridge_retained void *)block;
    my_async_function(my_callback, udata);
}

void my_callback(void *udata)
{
    dispatch_block_t block = (__bridge_transfer dispatch_block_t)udata;
    block();
}
\uuuuu bridge\u reserved
\uuuuu bridge\u transfer
在许多情况下工作良好,但在块上,它们会导致非常奇怪的行为

myAsyncFunction的汇编代码:完全没有retain(Xcode 4.4,ARC,O3)

非常奇怪的是,以下内核生成了一个
objc_retainBlock
,这是我对myasync函数的期望:

void *a_global_var;

- (void)myAsyncFunction2:(dispatch_block_t)block
{
    void *udata = (__bridge_retained void *)block;
    a_global_var = udata;
    my_async_function(my_callback, udata);
}
我们能称之为编译器的错误吗? 如果不是,编译器遵循什么规则

类似主题:

试试:

- (void)myAsyncFunction:(dispatch_block_t)block
{
    void *udata = (__bridge_transfer void *) [block copy];
    my_async_function(my_callback, udata);
}

void my_callback(void *udata)
{
    // however, see the comment in the last paragraph
    dispatch_block_t block = (__bridge_transfer dispatch_block_t)udata;
    block();
}
通常,当您将块指针指定给某个位置时,编译器会在
块复制
调用中进行合成

但是,在将void*传递到C api之后,编译器无法知道它会发生什么,而且无论如何,您正在重写编译器可能认为它应该对
\uuu bridge\u retained
调用执行的任何操作。存储引用时保留块是不够的

此外,即使进行了此更改,您的回调也必须被精确调用一次,因为它负责释放块。如果没有人打电话,你会漏掉的。如果它被多次调用,您将崩溃。因此,您可能希望让包装器类的实例负责管理块的内存,除非C api允许您提供一个清理函数,您可以使用它来释放块。

我读了一篇非常好的文章,现在明白了块必须被复制。正如您所说的,在存储引用时保留块是不够的。因此,正如您所建议的,在将其转换为void*之前复制它是正确的。我仍然想知道为什么编译器不保留它,即使在这里保留是不够的。