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

Difference between weak references in a block and a NSTimer

正如我们所知,我们需要在块内使用弱引用来打破保留循环,如下所示:

__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

有什么区别?计时器怎么还能保留目标呢?

基于选择器的 NSTimer 技术的全部问题是它建立了对传递给它的对象的强引用。因此,您用来保存对传递给 scheduledTimerWithTimeInterval 的目标的引用的变量本身是强还是弱并不重要。假设在基于选择器的调度计时器被调度时 target 引用不是 nilNSTimer 将建立自己的强引用。 "weak" 与 "strong" 调用代码中引用的性质仅指示 ARC 将在调用者代码中放置其自己的内存管理调用的位置,但 target 只是一个简单的指针,并且 none 的这种弱 vs 强信息被传达给 NSTimer。基于选择器的 NSTimer 将建立自己的强引用,直到计时器 invalidated.

才会解析

这就是为什么当我们想要使通过基于选择器的方法构建的计时器无效时,我们必须在 viewDidDisappear 等中而不是 dealloc.

注意,scheduledTimerWithTimeInterval 现在有 iOS 10 及更高版本的基于块的变体,因此如果您不必支持更早的版本,您可以享受块的弱引用模式 iOS 版本:

typeof(self) __weak weakSelf = self;
[NSTimer scheduledTimerWithTimeInterval:30 repeats:true block:^(NSTimer * _Nonnull timer) {
    // use weakSelf here
}];