递归块保留周期 [英] Recursive Block Retain Cycles

查看:62
本文介绍了递归块保留周期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这会导致任何形式的保留周期吗?使用安全吗?

__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.

证明这一点的最佳方法是尝试在分配"工具下运行,关闭停止时丢弃未记录的数据",打开记录参考计数",并关闭仅跟踪活动分配". /p>

我使用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),将控制台"更改为对象列表",然后将该地址粘贴到了搜索框中.仪器向我显示的只是该块的分配:

实时"列下的点表示在程序退出时仍在分配该块.它被泄漏了.我单击了地址旁边的箭头,以查看该块分配的完整历史记录:

此分配只发生过一件事情:已分配.

接下来,我在if (i == 0)语句中取消注释myBlock = nil行.然后,我再次将其运行在分析器下.为了安全起见,系统随机分配了内存地址,因此我清除了搜索栏,然后再次在控制台上检查运行时该块的地址.这次是0x7fc7a1424700.我再次切换到对象列表"视图,并粘贴到新地址0x7fc7a1424700中.这是我所看到的:

这次,实时"列下没有任何点,这意味着在程序退出时该块已被释放.然后,我点击了地址旁边的箭头以查看完整的历史记录:

这次,该块已分配,释放和释放.

Will this lead to any sort of retain cycle? Is it safe to use?

__block void (^myBlock)(int) = [^void (int i)
{
    if (i == 0)
        return;

    NSLog(@"%d", i);
    myBlock(i - 1);
} copy];
myBlock(10);

myBlock = nil;

解决方案

Your code does contain a retain cycle, but you can break the retain cycle at the end of the recursion by setting myBlock to nil in the recursion base case (i == 0).

The best way to prove this is to try it, running under the Allocations instrument, with "Discard unrecorded data upon stop" turned off, "Record reference counts" turned on, and "Only track active allocations" turned off.

I created a new Xcode project using the OS X Command-Line Tool template. Here's the entire program:

#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;
}

Then I ran it under the Allocations instrument, with the settings I described above. Then I changed "Statistics" to "Console" in Instruments, to see the program output:

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>

I copied the block address (0x7ff142c24700), changed "Console" to "Objects List", and pasted the address into the search box. Instruments showed me just the allocation for the block:

The dot under the Live column means the block was still allocated when the program exited. It was leaked. I clicked the arrow next to the address to see the full history of the block's allocation:

Only one thing ever happened with this allocation: it was allocated.

Next I uncommented the myBlock = nil line in the if (i == 0) statement. Then I ran it under the profiler again. The system randomizes memory addresses for security, so I cleared out the search bar and then checked the Console again for the block's address on this run. It was 0x7fc7a1424700 this time. I switched to the "Objects List" view again and pasted in the new address, 0x7fc7a1424700. Here's what I saw:

There's no dot under the Live column this time, meaning that the block had been freed by the time the program exited. Then I clicked on the arrow next to the address to see the full history:

This time, the block was allocated, released, and freed.

这篇关于递归块保留周期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆