我已经知道了块保留周期引起的内存泄漏。我只想要一个简单的规则,我可以应用于我的代码,以确保我避免它们。另一方面,我不想在没有必要的情况下将我的代码库的一半更新为__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; };
请提醒我上述任何错误的情况。
是否有更简单,更好的规则?
如果您可以添加一些解释来解释规则有效或无效的原因,那将是非常棒的。
基于答案的规则:考虑块中提到的所有对象并询问,这些对象中的任何一个都保留此块吗?
答案 0 :(得分:4)
保留周期是A - > B - > A(其中 - >表示保留)。这很糟糕,因为我们无法释放保留的东西,因此解除分配A的唯一方法是取消分配B,但这取决于取消分配A。
块保留周期没有什么不同,除了块对保留更具侵略性:它们保留在其中引用的任何对象,因此如果A - >阻止和阻止提到A,然后A - >;阻止 - >甲
所有这些都会在编码块时产生一个简单的规则。考虑块中提到的所有对象并询问,这些对象中的任何一个都保留此块吗?大多数时候他们没有。但要特别注意你传递块的对象,换句话说:
[beSuspiciousOfMe heresABlock:^{
NSLog(@"does %@ retain this block?", beSuspiciousOfMe];
}];
如果您控制beSuspiciousOfMe(可以是,通常是自己),这很容易检查。如果该代码由于某种原因不透明,并且您不确定,则可以使用__weak复制技巧。