在执行期间将块设置为nil时会发生什么?

时间:2012-09-04 23:49:54

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

假设我有一个对块有强引用的对象。在执行该块的某个时间,强引用设置为nil。块是否保证完成执行,或者这会导致崩溃?我见过exc-bad-access错误,但是我无法可靠地生成它们,所以我不知道它们为什么会弹出来。

例如:

-(void)method
{
    self.block = ^{
        //code
        self.block = nil;
        //more code - crash here?
    }
}

-(void)otherMethod
{
    block();
}

3 个答案:

答案 0 :(得分:3)

文档似乎不保证块在执行时会被保留。相反,诸如dispatch_async之类的GCD调用的文档确实提供了这样的保证。从那看起来你似乎不能假设对块的普通调用会保留它。

所以在你的代码中你可能想要:

-(void)otherMethod
{
    dispatch_block_t localBlock = Block_copy(block);
    localBlock();
    Block_release(localBlock);
}

答案 1 :(得分:3)

我相信我终于对这个问题有了满意的答案。请注意,这完全在ARC的上下文中。

块可以在执行期间解除分配。该块将继续正常执行,但其捕获变量的任何指针都会变得可疑(并且可能存在危险)。

假设ObjectA具有名为completion的块复制属性:

@property (nonatomic, copy) void (^completion)();

...赋值看起来像这样:

__weak ObjectA * weakSelf = self;
self.completion = ^{
    weakSelf.completion = nil;
    [weakSelf doSomethingElse];
};

如果像这样调用块......

-(void)method
{
    _completion(); //directly uses ObjectA's instance of the block
}

...然后,假设没有其他任何东西对该块的这个实例有引用,它就会被解除分配并且其捕获的变量weakSelf变为零。永远不会调用doSomethingElse。解决此问题的最佳方法是使用其访问器简单地调用块 - 这将在堆栈上分配新副本。原始文件将被解除分配,但新副本及其所有捕获的变量将在当前上下文中存活。

-(void)method
{
    self.completion(); //uses new copy of the block
}

答案 2 :(得分:1)

当执行块的方法没有首先检查是否仍然存在对块的引用时,可能会发生崩溃。你可能已经在方法中遇到了这样的问题,就像这个缺失一样。

- (void)methodWithBlock:(void (^)(void))block
{
   if (block) // this check is to prevent crashes when calling to a released block pointer ...
   {
      block();
   }
}

您可能遇到过丢失此类检查的代码,这可能导致您遇到的崩溃。我当然也经历过同样的事情。