有关为什么此代码在Sample
方法之后泄漏(过度保留)[startSampling:action:]
类的实例的任何想法? Profiler在采样完成后显示正保留计数(即sample()
块返回YES
)。 ARC显然已启用。
@implementation Sample
- (void)startSampling:(BOOL (^)(Sample *sender))sample action:(void (^)(Sample *sender))action {
__block void (^next)(Sample *sender) = nil;
void (^block)(Sample *sender) = ^(Sample *sender) {
if (sample(sender)) {
action(sender);
} else {
[self performBlock:next afterDelay:self.duration / 100.0];
}
};
next = block;
[self performBlock:block afterDelay:self.duration / 100.0];
}
@end
答案 0 :(得分:4)
您正在使用该方法创建一个块。该块本质上是一个struct
,其中包含块使用的每个外部定义变量的字段,以及一些额外的内容,例如指向要为块运行的代码的指针:
struct TheBlock {
void (*function)(TheBlock *);
// other bookkeeping fields
__strong TheBlock *next;
__strong OtherBlockType *sample;
__strong OtherBlockType *action;
__strong Sample *self;
};
执行next = block;
时,您将next
字段设置为指向包含它的结构。因此块保留自身,这是一个保留周期,防止块被释放。该块还保留self
,阻止Sample
实例被释放。
解决此问题的一种方法是在完成后将next
设置为nil
:
void (^block)(Sample *sender) = ^(Sample *sender) {
if (sample(sender)) {
action(sender);
next = nil;
} else {
[self performBlock:next afterDelay:self.duration / 100.0];
}
};
这将在不再需要块时中断保留周期,允许块和Sample
实例被释放。
答案 1 :(得分:2)
块捕获变量next
。块在复制时保留任何捕获的对象指针类型的变量(实际上,因为它是块指针类型的变量,所以它被复制而不是保留)。在ARC下,也会保留__block
个变量。 next
设置为指向块,因此块具有对其自身的强引用。这就是你有一个保留周期的原因。
要解决此问题,您只需将next
作为弱引用:
__block __weak void (^next)(Sample *sender) = nil;