当应用程序进入后台时如何暂停 Timer()

How to pause Timer() when the app goes into the background

所以我被卡住了,我正在构建一个宾果应用程序,我希望该应用程序在进入后台时停止计时器。我的代码看起来像这样

var timer = Timer()

func ViewDidLoad(){
    // other stuff
    timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(numberPicker), userInfo: nil, repeats: true)
}

在我读到的其他帖子中,我看到有人建议将计时器定义为弱变量。当我尝试这个时,我的应用程序在尝试设置计时器时崩溃了。

试试这个。当应用程序从后台 returns 时,计时器也会重新启动。

class ViewController: UIViewController {

    var timer = Timer()
    var timerPaused = false

    override func viewDidLoad() {
        super.viewDidLoad()
        NotificationCenter.default
            .addObserver(self,
                         selector: #selector(applicationDidEnterBackground),
                         name: UIApplication.didEnterBackgroundNotification,
                         object: nil)
        NotificationCenter.default
            .addObserver(self,
                         selector: #selector(applicationDidBecomeActive),
                         name: UIApplication.didBecomeActiveNotification,
                         object: nil)
        timer = Timer.scheduledTimer(timeInterval: 5,
                                     target: self,
                                     selector: #selector(numberPicker),
                                     userInfo: nil,
                                     repeats: true)
    }

    @objc
    func applicationDidEnterBackground(_ notification: Notification) {
        if !timerPaused {
            timer.invalidate()
            timerPaused = true
        }
    }

    @objc
    func applicationDidBecomeActive(_ notification: Notification) {
        if timerPaused {
            timer = Timer.scheduledTimer(timeInterval: 5,
                                     target: self,
                                     selector: #selector(numberPicker),
                                     userInfo: nil,
                                     repeats: true)
            timerPaused = false
        }
    }

    @objc
    func numberPicker(_ sender: Any) {

    }

}

Swift 5:

override func viewDidLoad() {
        super.viewDidLoad()
        let notificationCenter = NotificationCenter.default
        notificationCenter.addObserver(self, selector: #selector(appMovedToBackground), name: UIApplication.willResignActiveNotification, object: nil)
    }

    @objc func appMovedToBackground() {
        timer.invalidate()
    }

现代解决方案是 DispatchSourceTimer 可以暂停和恢复。

两个通知观察者也使用现代 swifty 基于块 API,不需要 @objc

let timer = DispatchSource.makeTimerSource(queue: DispatchQueue.global())

override func viewDidLoad() {
    super.viewDidLoad()
    timer.schedule(deadline: .now() + .seconds(5), repeating: 5.0)
    timer.setEventHandler {
        print("Timer fired")
    }

    NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { [weak self] _ in
        self?.timer.suspend()
    }
    NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main) { [weak self] _ in
        self?.timer.resume()
    }

    timer.activate()
}