Objective-C块中的代码如何引用块对象本身?

时间:2011-03-05 02:38:34

标签: objective-c objective-c-blocks

self仅仅是块内的捕获变量,并不引用块本身,那么块如何在没有为此目的的显式捕获变量的情况下引用自身?

5 个答案:

答案 0 :(得分:16)

__block void(^strawberryFields)();
strawberryFields = [^{ strawberryFields(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
               strawberryFields);
  • 您使用__block,因为该块会在创建块时创建strawberryFields的值的副本,该块将在分配之前。< / p>

  • 在任何其他复制操作之前,您还必须copy块,否则您最终会得到一个引用堆栈原始版本的块。

  • 请注意,上面的代码会泄漏块。在某个地方,需要有release的块来平衡副本。

答案 1 :(得分:5)

我发现这种模式在ARC(自动引用计数)中工作和稳定,无论是在Debug和Release版本中。

-(void) someMethod
{
    // declare a __block variable to use inside the block itself for its recursive phase.
    void __block (^myBlock_recurse)();

    // define the block
    void (^myBlock)() = ^{
        // ... do stuff ...
        myBlock_recurse(); // looks like calling another block, but not really.
    };

    // kickstart the block
    myBlock_recurse = myBlock; // initialize the alias
    myBlock(); // starts the block
}

最初我尝试将__block修饰符添加到myBlock并直接使用该变量在块的实现中递归。这适用于ARC Debug构建,但在Release构建中以EXC_BAD_ACCESS中断。另一方面,删除__block修饰符会引发“当被块捕获时未定义的变量”警告(我不愿意运行它并进行测试)。

答案 2 :(得分:0)

我之前从未尝试过这种做法,并且100%确定它是有用的,如果有效,但是例如:

typedef void (^BasicBlock)(void);

__block BasicBlock testBlock;
testBlock  = ^{NSLog(@"Testing %p", &testBlock);};
testBlock();

您可能已使用__block声明变量以防止自我保留循环。

答案 3 :(得分:0)

该块需要一些方法来取消自己的引用。通常,它是通过将块存储在类的属性中来完成的。

有时你可能更喜欢不使用财产。以下是没有财产的方法:

    __weak id weakSelf = self;
    __block id block = ^{

        if(weakSelf) {

            // .. do whatever

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);
        }
        else {

            block = nil;
        }
    };

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);

要记住的关键是所有代码路径都必须导致block = nil。我们在这里通过每隔5秒调用一次块来做到这一点,直到weakSelf变为零。

答案 4 :(得分:0)

请注意,在ARC中,它有点不同 - 默认情况下,__block对象指针变量保留在ARC中,与MRC不同。因此,它将导致保留周期。块必须捕获对自身的弱引用(使用__weak)才能没有保留周期。

但是,我们仍然需要在某个地方强烈引用该块。如果没有强引用,则将释放该块(自复制后在堆上)。因此,我们需要两个变量,一个是强,一个是弱,而在块内部使用弱变量来引用自身:

__block __weak void(^weakBlock)();
void(^myBlock)();
weakBlock = myBlock = [^{ weakBlock(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
               myBlock);