运行 后台计时器

Run timer in background

在iOS系统应用程序时钟中,当我启动计时器或秒表、退出应用程序、终止并重新打开它时,计时器或秒表仍然运行.

如何在后台设置 timer 运行?
苹果是怎么做到的?

关闭应用程序时,将当前计时器和时钟值存储在 UserDefault 中的长属性中(以秒或毫秒为单位)。我使用的是通用的,我可以分享:

static let userDefaults = UserDefaults.standard

    public static func set<T: Hashable> (withValue value: T, andKey key: String) {
        userDefaults.set(value, forKey: key)
        userDefaults.synchronize()
    }
    public static func get(forKey key: String) -> Any? {
        if((userDefaults.object(forKey: key)) != nil){
            let data = userDefaults.object(forKey: key) as? Any
            return data
        }
        return nil
    }

再次启动应用时,使用"get"方法获取;让我们说秒和存储时间。然后您可以将当前时间与存储的时间进行比较并计算两者之间的秒数并将时差添加到存储的秒数中,您只需将计时器设置为当前值并继续运行即可。

关闭应用程序时的设置方法如下:

NotificationCenter.default.addObserver(self, selector: #selector(storeTime), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)

func storeTime() {
     "UserDefaultClassName".set(withValue: "preferably dictionary", andKey: String)
}

可以通过在后台识别对 运行 的请求的令牌来实现。
像这样:var bgTask = UIBackgroundTaskIdentifier()

使用方法如下:

var bgTask = UIBackgroundTaskIdentifier()
    bgTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
        UIApplication.shared.endBackgroundTask(bgTask)
    })
    let timer = Timer.scheduledTimer(timeInterval: 10, target: self, selector: #selector(notificationReceived), userInfo: nil, repeats: true)
    RunLoop.current.add(timer, forMode: RunLoopMode.defaultRunLoopMode)

希望有用!

将此代码添加到 appdelagate.swift

var backgroundUpdateTask: UIBackgroundTaskIdentifier = 0

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    return true
}

func applicationWillResignActive(application: UIApplication) {
    self.backgroundUpdateTask = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
        self.endBackgroundUpdateTask()
    })
}

func endBackgroundUpdateTask() {
    UIApplication.sharedApplication().endBackgroundTask(self.backgroundUpdateTask)
    self.backgroundUpdateTask = UIBackgroundTaskInvalid
}

func applicationWillEnterForeground(application: UIApplication) {
    self.endBackgroundUpdateTask()
}