首页 > 解决方案 > 在后台安排计时器

问题描述

我正在开发一个具有非常重要的流动时刻的应用程序。在前台和后台每x秒保存一次数据。我知道计时器运行时间不长,所以我添加了:

  1. 进入后台的bg任务
  2. 每x小时唤醒一次暂停的应用程序

这是代码:

class BackgroundTimer {

    private var bgTask: UIBackgroundTaskIdentifier = .invalid
    private var timer: Timer?
    private var wakeUpTimer: Timer?

    init() {
        addNotifications()
        startTimer()
        startWakeUpTimer()
    }

    // MARK: Notifications

    private func addNotifications() {
        removeNotifications()
        NotificationCenter.default.addObserver(self, selector:  #selector(applicationDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector:  #selector(applicationDidBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil)
    }

    private func removeNotifications() {
        NotificationCenter.default.removeObserver(self)
    }

    @objc private func applicationDidEnterBackground() {
        stopBackgroundTask()
        startBackgroundTask()
    }

    @objc private func applicationDidBecomeActive() {
        stopBackgroundTask()
    }

    // MARK: Timer

    public func startTimer() {
        stopForegroundTask()
        startForegroundTask()
    }

    private func fireTimer(_ timer: Timer) {

        // Run code every 30 sec
        // here
        // -----------

        stopBackgroundTask()
        startBackgroundTask()
    }

    private func startForegroundTask() {
        timer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true, block: fireTimer)
    }

    private func stopForegroundTask() {
        timer?.invalidate()
        timer = nil
    }

    // MARK: Background task

    private func startBackgroundTask() {

        guard timer != nil else { return }

        let state = UIApplication.shared.applicationState
        guard ((state == .background || state == .inactive) && bgTask == .invalid) else { return 
    }

        bgTask = UIApplication.shared.beginBackgroundTask(expirationHandler: { [weak self] in
            self?.stopBackgroundTask()
        })
    }

    private func stopBackgroundTask() {

        guard bgTask != .invalid else { return }

        UIApplication.shared.endBackgroundTask(bgTask)
        bgTask = .invalid
    }

    // MARK: Wake up timer

    private func startWakeUpTimer() {

        let date = Date().addingTimeInterval(4 * 3600)
        let timer = Timer(fireAt: date, interval: 0, target: self, selector: #selector(fireWakeUpTimer), userInfo: nil, repeats: false)
        RunLoop.main.add(timer, forMode: .common)
    }

    @objc private func fireWakeUpTimer(_ timer: Timer) {
        startWakeUpTimer()
    }
}

但是,像往常一样,有些东西效果不佳。定时器可以停止或唤醒定时器没有启动。你有同样的经历吗?如何改进功能?

标签: swifttimernotificationsbackground

解决方案


推荐阅读