Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
467 views
in Technique[技术] by (71.8m points)

objective c - Recursive Block Retain Cycles

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;
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

block leaked

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:

block leaked detail

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:

block freed

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:

block freed detail

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...