Search code examples
iosblockgrand-central-dispatchautoreleaseretain-cycle

Why putting "self" in the GCD blocks will cause a memory leak?


I have read the great article write by benzado that using block will cause memory leak if we have a class variable retain the block itself, and the block retain "self", that cause a retain cycle.

How do I avoid capturing self in blocks when implementing an API?

But I don't understand why using GCD will cause the same problem? functions like dispatch_async() looks like a local variable for me that shouldn't be captured by the class itself?

And the official document said that we should put autorelease in the blocks to ensure that our objects are released in time.

In most of my IOS project, I use GCD like this:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,(unsigned long)NULL), ^(void) {

    NSDictionary *resultDic = [MyService loadData];

    dispatch_async(dispatch_get_main_queue(), ^{
        [self.delegate useData:resultDic];
    });
});

Now I need to change all of them to

__block MyClass *blockSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,(unsigned long)NULL), ^(void) {

    @autoreleasepool{
        NSDictionary *resultDic = [MyService loadData];

        dispatch_async(dispatch_get_main_queue(), ^{

            @autoreleasepool{
                [blockSelf.delegate useData:resultDic];
            }
        });

    }
});

??

It looks dirty. Does anyone have a clue how to do it in a right way?

BTW, if I called some functions in the block and use "self" or "self.delegate" in that functions, does it mean that I need to change all of then to something else? (and I don't know what to do to fix it)

FYI, my IOS project is builded in IOS8.1 and non-ARC environment.


Solution

  • @autoreleasepool isn't needed.

    To the block you pass to dispatch_async, block would be copied(Block_copy) to the heap, but it would be released(Block_release) immediately after it is called. So no retain cycle there.

    To all the block you are using in your project, if self has a strong reference to the block or a strong reference chain to the block, you should use __block MyClass *blockSelf = self; to avoid retain cycle.

    Note: __block MyClass *blockSelf = self; works in non-ARC, if you migrate to ARC, use __weak instead.