iOS中VC被弹出导航栈后是否短暂存活?定时器崩溃排查
问题诊断与修复方案
核心原因验证
你的怀疑完全正确——NSTimer会强持有目标对象。如果你的SwiftSimpleScheduler里的NSTimer把SKScene(或关联的VC)作为target,那么即便VC被弹出导航栈,NSTimer的强引用会死死攥住对象不让它释放,定时器自然会继续触发。这时候CURRENT_GAME_VC从导航栈里找不到对应实例返回nil,强制解包直接触发崩溃。
具体修复步骤
1. 给定时器加上弱引用,切断强持有链
NSTimer默认强引用target,改用block形式的初始化方法,在block里捕获weak引用的self,这样对象释放时能自动终止定时器:
// 替换原有NSTimer创建代码 Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self, weak scheduler] timer in guard let self = self, let scheduler = scheduler else { timer.invalidate() return } self.onTick() }
当self(SKScene/VC)被释放时,weak引用会变成nil,此时立即销毁定时器,从根源上避免无效触发。
2. 干掉强制解包,加安全校验
强制解包是崩溃的直接导火索,不管定时器问题是否解决,都必须给CURRENT_GAME_VC加安全访问逻辑:
// 替换原来的强制解包代码 guard let gameVC = CURRENT_GAME_VC else { // 做降级处理:停止调度器、打日志都可以 scheduler.stopAllTasks() return } // 再正常使用gameVC
3. 主动在VC销毁时终止定时器
在VC的deinit方法里主动调用调度器的销毁逻辑,同时打印日志确认对象是否真的被释放:
deinit { scheduler.invalidateAllTimers() // 假设调度器提供这个方法 print("GameVC/SKScene 已释放") }
如果日志没打印,说明还有其他强引用(比如闭包没捕获weak、代理没设为weak),得进一步排查。
额外排查方向
- 检查CURRENT_GAME_VC的实现:是否在VC弹出后,导航栈的
viewControllers数组没及时更新?可以在onTick里打印数组内容,确认是否真的没有GameVC实例。 - 确认调度器的生命周期:如果SwiftSimpleScheduler是全局对象或被其他强引用持有,就算VC释放了,调度器还活着,定时器也会继续跑。
内容的提问来源于stack exchange,提问作者OMGPOP
相关产品推荐
相关产品推荐

