块中的弱引用与NSTimer之间的差异

dar*_*fei 5 objective-c nstimer ios objective-c-blocks

我们知道我们需要在块内部使用弱引用来打破保留周期,如下所示:

__weak id weakSelf = self;
[self doSomethingWithABlock:^() {
    [weakSelf doAnotherThing];
}]
Run Code Online (Sandbox Code Playgroud)

但弱引用不能打破由a引起的保留周期NSTimer.

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

有什么不同?计时器如何仍然保留目标?

Rob*_*Rob 6

基于选择器的NSTimer技术的整个问题是它建立了对传递给它的对象的强引用.因此,用于保存对传递给目标的引用的变量scheduledTimerWithTimeInterval本身是强还是弱,都是无关紧要的.假设target参考不是nil基于选择器的预定计时器被安排的时间,NSTimer将建立自己的强引用.调用代码中引用的"弱"与"强"性质只决定了ARC在调用者代码中放置自己的内存管理调用的位置,但这target只是一个简单的指针,并且这些弱信息和强信息都没有传达给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
}];
Run Code Online (Sandbox Code Playgroud)