【问题标题】:wrap c callbacks by blocks (__bridge_transfer and blocks)按块包装 c 回调(__bridge_transfer 和块)
【发布时间】:2012-07-31 10:38:38
【问题描述】:

我正在为标准 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();
}

__bridge_retained__bridge_transfer 在很多情况下都能正常工作,但在块上,它们会导致非常奇怪的行为。

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

非常奇怪的是,下面的核心,生成了一个objc_retainBlock,这是我对myAsyncFunction的期望:

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);
}

我们可以称之为编译器的错误吗? 如果不是,编译器遵循什么规则?

类似主题:

【问题讨论】:

    标签: objective-c ios5 automatic-ref-counting objective-c-blocks


    【解决方案1】:

    试试:

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

    通常,当您将块指针分配给位置where it could outlive the block structure it references 时,编译器会在Block_copy 调用中进行综合。

    但是,编译器无法知道在将 void* 传递给 C api 之后会发生什么,并且无论如何,您正在覆盖编译器可能认为它应该对 __bridge_retained 调用执行的任何操作。在存储引用时保留一个块是不够的。

    此外,即使进行了此更改,您的回调也必须只调用一次,因为它负责释放块。如果它永远不会被调用,您将泄漏该块。如果它被多次调用,你就会崩溃。所以你可能想让你的包装类的实例负责管理块的内存,除非 C api 允许你提供一个清理函数,你可以使用它来释放块。

    【讨论】:

    • 我读了this 非常好的文章,现在明白必须复制块。正如您所说,在存储引用时保留一个块是不够的。因此,正如您所建议的,在转换为 void * 之前复制它是正确的。我仍然想知道为什么编译器不保留它,即使在这里保留还不够。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-17
    • 1970-01-01
    相关资源
    最近更新 更多