我已经遇到了由块保留周期引起的内存泄漏。我想要一个简单的规则,我可以将它应用到我的代码中,以确保我避免使用它们。另一方面,我不想在没有必要的情况下将我的代码库的一半更新为 __weak
指针。
这是我目前所拥有的:
使用以下内容时不会出现内存泄漏:
dispatch_async(queue, ^{...}); // GCD call.
[Foo bar:^{...}]; // Class "+" methods with completion block.
但是,这些情况肯定会导致块保留周期内存泄漏:
self.myPropertyBlock = ^{ self; };
_myInstanceVariableBlock = ^{ self; };
self.myPropertyBlock = ^{ _selfInstanceVariable; };
obj.myPropertyBlock = ^{ obj; };
这些情况可能会也可能不会导致块保留周期内存泄漏(取决于块调用对象是否保留块):
[self bar:^{ self; }];
[self.myPropertyObj bar:^{ self; }];
[self.myPropertyObj bar:^{ _selfInstanceVariable; }];
[obj bar:^{ obj; }];
[obj.myPropertyObj bar:^{ obj; }];
为了绝对确保没有内存泄漏,有问题的情况需要将块内使用的
self
或 obj
指针更改为这样的 __weak
指针(或其他一些避免泄漏的策略):__weak SelfClass *weakSelf = self;
self.myPropertyBlock = ^{ weakSelf; };
_myInstanceVariableBlock = ^{ weakSelf; };
self.myPropertyBlock = ^{ weakSelf.instanceVariableConvertedToProperty; };
[self bar:^{ weakSelf; }];
[self.myPropertyObj bar:^{ weakSelf; }];
[self.myPropertyObj bar:^{ weakSelf.instanceVariableConvertedToProperty; }];
__weak ObjClass *weakObj = obj
[obj bar:^{ weakObj; }];
[obj.myPropertyObj bar:^{ weakObj; }];
obj.myPropertyBlock = ^{ weakObj; };
请提醒我上述任何错误情况。
有没有更简单更好的规则?
如果您可以添加一些解释来解释规则为何有效或无效,那就太棒了。
基于答案的规则:考虑块中提到的所有对象并问,这些对象中是否有任何保留该块?
最佳答案
保留周期是 A -> B -> A(其中 -> 表示保留)。这很糟糕,因为我们不能释放保留的东西,所以释放 A 的唯一方法是释放 B,但这取决于释放 A。
块保留循环没有什么不同,除了块在保留方面更加积极:它们保留其中引用的任何对象,因此如果 A -> Block 和 Block 提到 A,则 A -> Block -> A。
所有这些都导致在编码块时有一个简单的规则。考虑块中提到的所有对象并问,这些对象中的任何一个都保留了这个块吗?大多数时候他们不会。但是要特别注意您将块传递给的对象,换句话说:
[beSuspiciousOfMe heresABlock:^{
NSLog(@"does %@ retain this block?", beSuspiciousOfMe];
}];
如果您控制 beSuspiciousOfMe(可以是并且通常是 self),则很容易检查。如果该代码由于某种原因不透明,并且您不确定,则可以使用 __weak 复制技巧。
关于ios - 避免objective-c块保留循环内存泄漏的简单规则是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23691579/