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

调用NSTimer invalidate并置nil后偶现崩溃问题排查

关于NSTimer invalidate后置nil偶现野指针崩溃的原因分析

问题背景

你提到在主线程初始化NSTimer,调用-[invalidate]后立刻将timer置为nil时,偶现Bad access野指针崩溃,崩溃栈显示在resetTimerAndAnimation方法中触发了objc_msgSend错误。

崩溃日志如下:

#0. Crashed: com.apple.main-thread
0  libobjc.A.dylib                0x1819d4430 objc_msgSend + 16
1  MTXX                           0x100d73480 -[MTBDummyWebViewViewController resetTimerAndAnimation] (MTBDummyWebViewViewController.m:135)
2  MTXX                           0x100d73828 -[MTBDummyWebViewViewController webView:shouldStartLoadWithRequest:navigationType:] (MTBDummyWebViewViewController.m:176)
3  UIKit                          0x18bda4f9c -[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 300
4  CoreFoundation                 0x182779670 __invoking___ + 144
5  CoreFoundation                 0x1826586cc -[NSInvocation invoke] + 292
6  CoreFoundation                 0x18265d16c -[NSInvocation invokeWithTarget:] + 60
7  WebKitLegacy                   0x18b811858 -[_WebSafeForwarder forwardInvocation:] + 156
8  CoreFoundation                 0x1827773bc ___forwarding___ + 624
9  CoreFoundation                 0x18265d01c _CF_forwarding_prep_0 + 92
10 CoreFoundation                 0x182779670 __invoking___ + 144
11 CoreFoundation                 0x1826586cc -[NSInvocation invoke] + 292
12 WebCore                        0x18a4d34f4 HandleDelegateSource(void*) + 108
13 CoreFoundation                 0x18271a2e8 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
14 CoreFoundation                 0x18271a268 __CFRunLoopDoSource0 + 88
15 CoreFoundation                 0x182719af0 __CFRunLoopDoSources0 + 204
16 CoreFoundation                 0x1827176c8 __CFRunLoopRun + 1048
17 CoreFoundation                 0x182637fb8 CFRunLoopRunSpecific + 436
18 GraphicsServices               0x1844cff84 GSEventRunModal + 100
19 UIKit                          0x18bc0c2e8 UIApplicationMain + 208
20 MTXX                           0x10047f6bc main (main.m:15)
21 libdyld.dylib                  0x18215a56c start + 4

你的代码调用方式:

[self.timeoutTimer invalidate];
self.timeoutTimer = nil;

崩溃原因分析

这个偶现崩溃的核心问题出在**NSTimer的生命周期和RunLoop回调的时序上**:

  • 当你调用[self.timeoutTimer invalidate]时,NSTimer会被从RunLoop中移除,但RunLoop的任务队列里可能已经存在待执行的timer回调任务,或者像你的崩溃栈显示的那样,WebKit的回调链中还持有这个timer的旧引用。
  • 你在invalidate后立刻将self.timeoutTimer置为nil,此时timer对象的引用计数变为0,会被系统释放。但如果后续有异步触发的逻辑(比如WebView的导航回调)尝试访问这个已经被释放的timer对象,就会触发objc_msgSend的野指针错误。
  • 另外,NSTimer初始化时会对其target(也就是你的ViewController)产生强引用,虽然invalidate会解除这个强引用,但如果在invalidate的内部逻辑还没完全完成时,你就提前把timer置为nil,也可能导致后续的消息发送到已释放的内存。

简单的修复建议

  • 延迟置nil:在调用invalidate后,通过主队列的异步 dispatch 来延迟置nil,给系统足够的时间完成timer的清理逻辑:
[self.timeoutTimer invalidate];
dispatch_async(dispatch_get_main_queue(), ^{
    self.timeoutTimer = nil;
});
  • 使用弱引用封装:可以自定义一个基于弱引用target的NSTimer封装,避免循环引用和野指针问题,比如用iOS 10+支持的+[NSTimer scheduledTimerWithTimeInterval:repeats:block:]API,内部自动处理弱引用。

内容的提问来源于stack exchange,提问作者bool chow

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:16:29