You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何调用invalidate后NSTimer的retainCount仍不为零?

问题解答

嗨,这其实是iOS开发里一个很常见的误区,核心原因在于**retainCount本身就是个不可靠的调试工具**,再结合NSTimer和RunLoop的交互逻辑,就出现了你看到的结果,下面具体拆解:

1. 初始计数为3的来源

当你调用scheduledTimerWithTimeInterval:这个类方法时,系统会悄悄做这几件事:

  • 创建NSTimer实例,此时对象自身的初始retain计数为1
  • 自动把这个timer注册到当前线程的RunLoop(默认是主线程RunLoop)的NSDefaultRunLoopMode中,RunLoop会对timer做一次retain,计数+1
  • 你的局部变量timer持有了这个实例,又触发一次retain,计数+1
    三者加起来,就得到了初始的3。

2. invalidate后计数变为2的原因

调用[timer invalidate]时,系统会执行这些操作:

  • 把timer从RunLoop中移除,RunLoop释放对它的引用,计数减1(此时计数变为2)
  • 但你的局部变量timer还保持着对这个对象的强引用,所以计数不会再往下掉
  • 另外,系统内部可能还有临时的autorelease引用(比如方法调用过程中产生的临时持有,还没被autorelease pool回收),这也会让计数维持在2而不是1。

关键提醒:别靠retainCount判断对象死活

苹果官方文档早就明确说了,retainCount的返回值根本没法准确反映对象的实际引用情况——系统框架内部有大量你看不到的隐式retain/release操作,比如RunLoop的持有、autorelease pool的临时引用等,这些都会干扰计数结果。

如果想确认timer会不会被释放,正确的做法是:

  • 调用invalidate后,立刻把timer变量置为nil,解除你的强引用
  • 可以给NSTimer子类加个dealloc方法(或者用关联对象监听),看对象会不会触发销毁逻辑,这比看retainCount靠谱多了

内容的提问来源于stack exchange,提问作者Yanzhang Fu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:39:48