无效

时间:2018-05-09 14:16:36

标签: ios nstimer

我做了一些测试,并对结果感到困惑。

NSTimer  *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(runTimer) userInfo:nil repeats:YES];
NSLog(@"Timer Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)timer));

[timer invalidate];

NSLog(@"Timer Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)timer));

结果:

  

2018-05-09 21:57:35.708544 + 0800 newtest [539:96880]定时器保留计数为3

     

2018-05-09 21:57:40.104955 + 0800 newtest [539:96880]定时器保留计数为2

为什么NSTimer retainCount在无效后不为零?

2 个答案:

答案 0 :(得分:2)

要知道为什么保留计数不为零,这不是你的事。保留计数是一个实现细节,如果你可以避免它,最好不要注意它们。

以下是invalidate的文档说明的内容:

  

NSRunLoop对象在invalidate方法返回之前或之后的某个时间点删除了对计时器的强引用。

因此,当invalidate返回时,甚至不能保证减少保留计数。

此外,我们无法看到对象的保留计数为零。当保留计数变为零时,对象将被销毁,而您无法对被破坏的对象进行操作(例如,调用CFGetRetainCount)。对象的内存可能已被覆盖,因此尝试对其执行任何操作都是未定义的行为。

但是,我们可以对invalidate之后保留计数仍为2的原因进行一些猜测。

首先,我们知道您的本地timer变量对计时器有强烈的引用,因此会占用保留计数+1。

scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:选择器不以newalloccopy开头,因此它可能会自动释放该对象。这可能是保留计数中的另一个+1;该对象可能在自动释放池中。有关详细信息,请参阅Advanced Memory Management Programming Guide

您可以像这样测试自动释放理论:

NSTimer *timer;
@autoreleasepool {
    timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(runTimer) userInfo:nil repeats:YES];
    NSLog(@"Timer Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)timer));

    [timer invalidate];
    NSLog(@"Timer Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)timer));
}

NSLog(@"Timer Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)timer));
// If the retain count is now 1, the timer was in the autoreleasepool,
// and the local `timer` variable now has the only strong reference to
// the timer.

答案 1 :(得分:0)

Rob的解释是对的。

我只是添加了一些细节来证明scheduledTimerWithTimeInterval:target:selector:userInfo:repeats调用返回autorelase个对象。

在XCode中,您可以使用Product->执行操作 - >汇编以查看汇编代码

bl  _objc_msgSend
mov  x29, x29   ;
bl  _objc_retainAutoreleasedReturnValue; Here you see that the return value is Autoreleased

所以,在invalid

之前
  • 自动释放=> + 1
  • runloop => + 1
  • retain => + 1

结果是3

invalid之后

  • 自动释放=> 1
  • retain => 1

结果是2

如果您懂中文,可以阅读我的blog以查看有关ARC的更多详细信息。