为什么在GCD块中放入"self"会导致内存泄漏?
Why putting "self" in the GCD blocks will cause a memory leak?
我读过 benzado 写的很棒的文章,如果我们有一个 class 变量保留块本身,并且块保留 "self",则使用块会导致内存泄漏,这会导致保留循环.
How do I avoid capturing self in blocks when implementing an API?
但是我不明白为什么使用GCD会出现同样的问题?像 dispatch_async() 这样的函数对我来说看起来像是一个局部变量,不应该被 class 本身捕获?
而且官方文档说我们应该把autorelease放在blocks里面,保证我们的对象及时释放。
在我的大部分 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",这是否意味着我需要将所有 then 更改为其他内容? (而且我不知道该怎么做才能修复它)
仅供参考,我的 IOS 项目是在 IOS8.1 和 non-ARC 环境中构建的。
不需要 @autoreleasepool
。
你传递给dispatch_async
的块,块会被复制(Block_copy)到堆中,但调用后会立即释放(Block_release)。所以那里没有保留循环。
对于你在项目中使用的所有块,如果self
对该块有强引用或对块的强引用链,你应该使用__block MyClass *blockSelf = self;
以避免循环引用.
注意:__block MyClass *blockSelf = self;
适用于非 ARC,如果您迁移到 ARC,请改用 __weak
。
我读过 benzado 写的很棒的文章,如果我们有一个 class 变量保留块本身,并且块保留 "self",则使用块会导致内存泄漏,这会导致保留循环.
How do I avoid capturing self in blocks when implementing an API?
但是我不明白为什么使用GCD会出现同样的问题?像 dispatch_async() 这样的函数对我来说看起来像是一个局部变量,不应该被 class 本身捕获?
而且官方文档说我们应该把autorelease放在blocks里面,保证我们的对象及时释放。
在我的大部分 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",这是否意味着我需要将所有 then 更改为其他内容? (而且我不知道该怎么做才能修复它)
仅供参考,我的 IOS 项目是在 IOS8.1 和 non-ARC 环境中构建的。
@autoreleasepool
。
你传递给dispatch_async
的块,块会被复制(Block_copy)到堆中,但调用后会立即释放(Block_release)。所以那里没有保留循环。
对于你在项目中使用的所有块,如果self
对该块有强引用或对块的强引用链,你应该使用__block MyClass *blockSelf = self;
以避免循环引用.
注意:__block MyClass *blockSelf = self;
适用于非 ARC,如果您迁移到 ARC,请改用 __weak
。