我做了一些测试,并对结果感到困惑。
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在无效后不为零?
答案 0 :(得分:2)
要知道为什么保留计数不为零,这不是你的事。保留计数是一个实现细节,如果你可以避免它,最好不要注意它们。
以下是invalidate
的文档说明的内容:
NSRunLoop
对象在invalidate方法返回之前或之后的某个时间点删除了对计时器的强引用。
因此,当invalidate
返回时,甚至不能保证减少保留计数。
此外,我们无法看到对象的保留计数为零。当保留计数变为零时,对象将被销毁,而您无法对被破坏的对象进行操作(例如,调用CFGetRetainCount
)。对象的内存可能已被覆盖,因此尝试对其执行任何操作都是未定义的行为。
但是,我们可以对invalidate
之后保留计数仍为2的原因进行一些猜测。
首先,我们知道您的本地timer
变量对计时器有强烈的引用,因此会占用保留计数+1。
scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
选择器不以new
或alloc
或copy
开头,因此它可能会自动释放该对象。这可能是保留计数中的另一个+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
:
结果是3
invalid
之后
结果是2
如果您懂中文,可以阅读我的blog以查看有关ARC的更多详细信息。