为什么将“self”放在GCD块中会导致内存泄漏?

时间:2015-02-06 02:16:57

标签: ios block grand-central-dispatch autorelease retain-cycle

我已经阅读了苯扎多撰写的伟大文章,如果我们有一个类变量保留块本身,并且该块保留“self”,那么使用block会导致内存泄漏,从而导致保留周期。

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

但是我不明白为什么使用GCD会导致同样的问题?像dispatch_async()这样的函数看起来像是一个不应被类本身捕获的局部变量?

官方文件说我们应该在块中放置自动释放,以确保我们的对象及时释放。

在我的大多数IOS项目中,我都使用GCD:

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];
    });
});

现在我需要将所有这些更改为

__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];
            }
        });

    }
});

??

看起来很脏。 有没有人知道如何以正确的方式做到这一点?

顺便说一下,如果我在块中调用了一些函数并在该函数中使用“self”或“self.delegate”,这是否意味着我需要将所有函数更改为其他内容? (我不知道该怎么做才能解决它)

仅供参考,我的IOS项目是在IOS8.1和非ARC 环境中构建的。

1 个答案:

答案 0 :(得分:3)

@autoreleasepool不需要。

对于传递给dispatch_async的块,块将被复制(Block_copy)到堆,但是在调用它之后会立即释放(Block_release)。所以那里没有保留周期。

对于您在项目中使用的所有块,如果self具有对块的强引用或块的强引用链,则应使用__block MyClass *blockSelf = self;以避免保留周期。 / p>

注意:__block MyClass *blockSelf = self;适用于非ARC,如果您迁移到ARC,请改用__weak