假设我有一个对块有强引用的对象。在执行该块的某个时间,强引用设置为nil。块是否保证完成执行,或者这会导致崩溃?我见过exc-bad-access错误,但是我无法可靠地生成它们,所以我不知道它们为什么会弹出来。
例如:
-(void)method
{
self.block = ^{
//code
self.block = nil;
//more code - crash here?
}
}
-(void)otherMethod
{
block();
}
答案 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();
}
}
您可能遇到过丢失此类检查的代码,这可能导致您遇到的崩溃。我当然也经历过同样的事情。