self
仅仅是块内的捕获变量,并不引用块本身,那么块如何在没有为此目的的显式捕获变量的情况下引用自身?
答案 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);