块中的弱引用和NSTimer之间的区别

5

我们知道,为了打破引用循环,我们需要在块内使用弱引用,像这样:

__weak id weakSelf = self;
[self doSomethingWithABlock:^() {
    [weakSelf doAnotherThing];
}]

然而,弱引用无法打破由NSTimer引起的保留循环。

__weak id weakSelf = self;
timer = [NSTimer scheduledTimerWithTimeInterval:30.0f 
                                         target:weakSelf
                                       selector:@selector(tick) 
                                       userInfo:nil
                                        repeats:YES]; // No luck

什么是区别?计时器如何仍保留目标?

顺便提一下,当定义“weakSelf”时,我们通常使用“typeof(self)”而不是“id”。 - Rob
1个回答

6
选择器基础的NSTimer技术存在的整个问题在于,它建立了对传递给它的对象的强引用。因此,无论你用来持有传递给scheduledTimerWithTimeInterval的目标引用的变量是strong还是weak,都是无关紧要的。假设在基于选择器的定时器被安排之前,目标引用不是nil,NSTimer将建立自己的强引用。调用代码中引用的“弱”与“强”的本质只决定ARC将在调用方的代码中放置其自己的内存管理调用的位置,但目标只是一个简单的指针,而且没有这种弱与强信息被传达给NSTimer。基于选择器的NSTimer将建立自己的强引用,直到计时器被使无效为止。
这就是为什么当我们想要使通过选择器方法构建的计时器变得无效时,我们必须要在viewDidDisappear或类似的地方去实现,而不是在dealloc里面。
注意,scheduledTimerWithTimeInterval现在已经有了基于block的iOS 10及更高版本的变体,因此如果你不需要支持早期iOS版本,则可以享受块的弱引用模式。
typeof(self) __weak weakSelf = self;
[NSTimer scheduledTimerWithTimeInterval:30 repeats:true block:^(NSTimer * _Nonnull timer) {
    // use weakSelf here
}];

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接