在块内调用Block_Release即可释放

时间:2015-08-16 23:18:47

标签: objective-c objective-c-blocks grand-central-dispatch

是否有可能在其内部释放一个块?对于编译器来说没问题,但是我不确定它是否会在运行时崩溃,因为它释放了同时执行的内存。

cancel_block_t someFunction(/*args*/){
    __block BOOL canceled = NO;
    __block cancel_block_t cancel_block = Block_copy(^{
        canceled = YES;
        Block_Release(cancel_block); //<-- can I do this?
        cancel_block = NULL; //<-- can I do this?
    });
    // […]
    return cancel_block;
}

这种方法会更安全吗?

 cancel_block_t someFunction(/*args*/){
    __block BOOL canceled = NO;
    __block cancel_block_t cancel_block = Block_copy(^{
        canceled = YES;
        dispatch_async(dispatch_time(DISPATCH_TIME_NOW, 0.001 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),^{
            Block_Release(cancel_block);
            cancel_block = NULL;
        });
    });
    // […]
    return cancel_block;
}

感谢您的帮助!

编辑#1:更正了函数的返回类型。

1 个答案:

答案 0 :(得分:1)

这是非ARC代码吗? ARC将自动复制,保留和释放块。

无论如何,这不安全,至少并非总是如此。我已经看到类似行为的崩溃。问题是对__block变量的引用位于Block_release()可能解除分配的同一块对象中。因此,尝试设置变量可以在释放(并且可能重用)后访问内存。

关于你的功能:

1)为什么它返回指向块类型的指针?函数返回块类型(已经是引用)更为正常。也就是说,someFunction()的返回类型应为cancel_block_t,而不是cancel_block_t*。无论如何,获取__block变量的地址是不安全的,因为这样的变量可以改变位置。它从堆栈开始,然后移动到堆中。

2)返回块的函数的正常语义是返回一个自动释放的对象。因此,someFunction()应该只是return [cancel_block autorelease];(因为它已被复制)。如果调用者想要将其保留在当前范围或自动释放池之外,则负责保留它。如果它已提交给函数(例如dispatch_async()),则该函数负责保留它。换句话说,内存管理语义与任何其他对象相同。该块不应该试图释放自己。