如何在ViewDidLoad外失效Timer?声明全局Timer触发SIGABRT错误求助
Let's break down what's happening with your Timer code, and how to fix both the "Timer失效" issue and the subsequent SIGABRT crash:
First: Why Your Original Local Timer Was "失效"
In your viewDidAppear method, you're creating a local Timer variable. As soon as the method finishes executing, ARC (Automatic Reference Counting) releases this Timer instance because there are no strong references keeping it alive. That's why it stops working after the first fire—there's no Timer left to repeat the task.
Second: Why the Global/Instance Timer Causes SIGABRT
When you move the Timer to a global or instance variable, you create a strong reference cycle (循环引用):
- The Timer holds a strong reference to its
target(your ViewController) - Your ViewController holds a strong reference to the Timer (via the global/instance variable)
Neither object can be properly deallocated when your ViewController is dismissed or popped. This leads to memory leaks, and eventually triggers a SIGABRT crash when the system tries to clean up these stuck objects.
The Fixes
Here are two reliable solutions, depending on whether you prefer block-based or selector-based Timer usage:
Solution 1: Block-Based Timer (Recommended, Avoids Cycle References)
First, declare an optional Timer instance variable in your ViewController:
private var updateTimer: Timer?
Then, create the Timer in viewDidAppear with a weak reference to self to break the cycle:
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // Don't forget to call super! updateTimer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { [weak self] _ in self?.updateOnlineTrack() } }
Finally, clean up the Timer when the ViewController disappears to avoid leaks:
override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) updateTimer?.invalidate() updateTimer = nil // Explicitly break the reference }
Solution 2: Selector-Based Timer (If You Prefer This Style)
Again, start with an optional instance variable:
private var updateTimer: Timer?
Update your viewDidAppear method (and don't forget super):
override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) updateTimer = Timer(timeInterval: 3, target: self, selector: #selector(updateOnlineTrack), userInfo: nil, repeats: true) RunLoop.current.add(updateTimer!, forMode: .default) updateTimer?.fire() }
Critical: Add cleanup code in viewDidDisappear to invalidate the Timer and break the cycle:
override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) updateTimer?.invalidate() updateTimer = nil }
Quick Notes
- Your
@objc private func updateOnlineTrack()is correctly declared—no issues there since the compiler accepts it. - Always call the
superimplementation of lifecycle methods likeviewDidAppearandviewDidDisappear—omitting this can cause unexpected behavior.
内容的提问来源于stack exchange,提问作者Max Kraev

