为了更好地说明这个问题,考虑块递归以下简化形式:
__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:你会是一个更好的实现块递归的?
谢谢。
为了完成保留周期,免费递归块的执行,就需要使用两个块参照 - 一个弱和强一个。 因此,对于你的情况,这是代码可能是什么样子:
__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对于这个模式中,也使用块递归的另一个例子。 此外,在下面的文章的评论部分的讨论与此相关的还有: http://ddeville.me/2011/10/recursive-blocks-objc/
我认为@newacct约为@马特威尔丁的解决方案正确; 它似乎没有什么会产生强烈的裁判在这种情况下,下一个和运行时会导致运行时异常(至少它为我做的)。
我不知道它是多么常见的发现递归调用块在objc野外。 然而,在现实世界中实现(如果实际需要)上说,一个视图控制器,一个可能定义块,然后建立一个内部的接口属性具有较强的参考所述块:
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
这将运行对我罚款,没有编译器警告有关保留周期(在仪表没有泄漏)。 不过,我想我可能会避开这样做在大多数情况下objc这个(递归块调用)的 - 它的臭。 但在任何情况下有趣。