5

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

例如:

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

-(void)otherMethod
{
    block();
}
4

3 回答 3

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 变为 nil。doSomethingElse 永远不会被调用。解决这个问题的最好方法是使用它的访问器简单地调用块——这将在堆栈上分配一个新副本。原始副本将被释放,但新副本及其所有捕获的变量将在当前上下文中继续存在。

-(void)method
{
    self.completion(); //uses new copy of the block
}
于 2013-06-25T14:54:22.813 回答
3

这些文件似乎不能保证在执行时会保留一个块。相反,诸如 GCD 调用的文档dispatch_async确实做出了这样的保证。由此看来,您似乎不能假设对块的普通调用会保留它。

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

-(void)otherMethod
{
    dispatch_block_t localBlock = Block_copy(block);
    localBlock();
    Block_release(localBlock);
}
于 2012-09-05T00:42:24.540 回答
1

当执行块的方法没有首先检查是否仍然存在对块的引用时,可能会发生崩溃。您可能已经在方法中遇到了这些崩溃,因为缺少这样的检查。

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

您可能遇到过缺少此类检查的代码,这可能会导致您遇到崩溃。我当然也有同样的经历。

于 2012-09-04T23:57:54.170 回答