Jeffrey Thomas 的答案很接近,但是在 ARC 下,它会泄漏块,而没有 ARC,它会崩溃。
如果没有 ARC,__block
变量就不会保留它所引用的内容。块是在堆栈上创建的。所以callback
变量指向堆栈上的一个块。当您第一次传递callback
到dispatch_after
(块外)时,dispatch_after
成功地在堆上制作了块的副本。但是,当该副本被调用并再次传递callback
给dispatch_after
时,callback
是一个悬空指针(指向堆栈上现在已销毁的块),并且dispatch_after
(通常)会崩溃。
使用 ARC,__block
块类型的变量(如callback
)会自动将块复制到堆中。所以你不会遇到崩溃。但是对于 ARC,__block
变量会保留它引用的对象(或块)。这导致了一个保留周期:块引用自身。Xcode 将在递归dispatch_after
调用中向您显示警告:“在此块中强烈捕获'回调'可能会导致保留周期”。
要解决这些问题,您可以显式复制块(将其从堆栈移动到 MRC 下的堆)并设置callback
为 nil(在 ARC 下)或释放它(在 MRC 下)以防止泄漏:
__block void (^callback)() = [^{
if(stop_) {
NSLog(@"all done");
#if __has_feature(objc_arc)
callback = nil; // break retain cycle
#else
[callback release];
#endif
} else {
NSLog(@"still going");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
}
} copy];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
显然,您可以删除#if
并只使用适合您的内存管理的分支。