阻止recursion并打破保留周期

为了更好地说明这个问题,请考虑以下简化forms的块recursion:

__block void (^next)(int) = ^(int index) { if (index == 3) { return; } int i = index; next(++i); }; next(0); 

XCode(支持ARC)警告说,“ 在这个块中强烈地捕获'下一个'可能会导致一个保留周期

同意。

问题1 :通过以下面的方式将块本身设置nil来保留周期是否成功:

 __block void (^next)(int) = ^(int index) { if (index == 3) { next = nil; // break the retain cycle return; } int i = index; next(++i); }; next(0); 

(注意:你仍然会得到同样的警告,但也许是没有根据的)

问题2 :什么是更好的块recursion实现?

谢谢。

为了完成无保留循环的recursion块的执行,你需要使用两个块引用 – 一个弱和一个强。 所以对于你的情况,这是代码可能是这样的:

 __block __weak void (^weak_next)(int); void (^next)(int); weak_next = next = ^(int index) { if (index == 3) { return; } int i = index; weak_next(++i); }; next(0); 

请注意,该块捕获弱块参考(weak_next),外部上下文捕获强参考(下一个)以保持块。 两个参考都指向同一个块。

有关此模式的另一个示例,请参阅https://stackoverflow.com/a/19905407/1956124 ,该模式也使用块recursion。 另外,以下文章的注释部分的讨论也与此处相关: http : //ddeville.me/2011/10/recursive-blocks-objc/

我认为@Matt Wilding的解决scheme@newacct是正确的; 在这种情况下,似乎没有什么东西可以强有力地引用下一个块,并且在运行时会导致运行时exception(至less对我来说是这样)。

我不知道在objc中寻找在野外recursion调用的块有多普遍。 然而,在现实世界的实现中(如果实际需要的话),视图控制器,可以定义块,然后build立一个内部接口属性,并强引用所述块:

 typedef void(^PushButtonBlock)(); @interface ViewController () @property (strong, nonatomic) PushButtonBlock pushButton; @end @implementation ViewController ... // (in viewDidLoad or some such) __weak ViewController *weakSelf = self; self.pushButton = ^() { [weakSelf.button pushIt]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), weakSelf.pushButton); }; self.pushButton(); ... @end 

这对我来说运行良好,并没有关于保留周期的编译器警告(并且仪器中没有泄漏)。 但是,我认为在大多数情况下,我可能会避免这样做(recursion块调用) – 它很臭。 但无论如何有趣。