这会导致任何形式的保留周期吗?使用安全吗?
__block void (^myBlock)(int) = [^void (int i)
{
if (i == 0)
return;
NSLog(@"%d", i);
myBlock(i - 1);
} copy];
myBlock(10);
myBlock = nil;
最佳答案
您的代码确实包含一个保留周期,但是您可以通过在递归基本情况下(myBlock
)将i == 0
设置为nil来中断递归结束时的保留周期。
证明这一点的最佳方法是尝试在“分配”工具下运行,关闭“停止时丢弃未记录的数据”,打开“记录引用计数”,并关闭“仅跟踪 Activity 分配”。
我使用OS X命令行工具模板创建了一个新的Xcode项目。这是整个程序:
#import <Foundation/Foundation.h>
void test() {
__block void (^myBlock)(int) = [^void (int i){
if (i == 0) {
// myBlock = nil;
return;
}
NSLog(@"myBlock=%p %d", myBlock, i);
myBlock(i - 1);
} copy];
myBlock(10);
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
test();
}
sleep(1);
return 0;
}
然后,使用上述设置在“分配”工具下运行它。然后在Instruments中将“统计信息”更改为“控制台”,以查看程序输出:
2012-10-26 12:04:31.391 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 10
2012-10-26 12:04:31.395 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 9
2012-10-26 12:04:31.396 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 8
2012-10-26 12:04:31.397 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 7
2012-10-26 12:04:31.397 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 6
2012-10-26 12:04:31.398 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 5
2012-10-26 12:04:31.398 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 4
2012-10-26 12:04:31.399 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 3
2012-10-26 12:04:31.400 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 2
2012-10-26 12:04:31.401 recursiveBlockTest[71789:303] myBlock=0x7ff142c24700 1
<End of Run>
我复制了块地址(
0x7ff142c24700
),将“控制台”更改为“对象列表”,然后将该地址粘贴到了搜索框中。仪器向我显示了该块的分配:“实时”列下的点表示程序退出时仍在分配该块。它被泄漏了。我单击了地址旁边的箭头,以查看块分配的完整历史记录:
此分配只发生过一件事情:已分配。
接下来,我取消对
myBlock = nil
语句中的if (i == 0)
行的注释。然后,我再次将其运行在分析器下。为了安全起见,系统随机分配了内存地址,因此我清除了搜索栏,然后再次在控制台上检查运行时该块的地址。这次是0x7fc7a1424700
。我再次切换到“对象列表” View ,然后粘贴到新地址0x7fc7a1424700
中。这是我所看到的:这次,“实时”列下没有任何点,这意味着在程序退出时该块已被释放。然后,我单击了地址旁边的箭头以查看完整的历史记录:
这次,该块已分配,释放和释放。
关于objective-c - 递归块保留周期,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13090598/