在Swift中简单的服务,坚持只有前台?
我只是想要运行一些东西
- 每20秒就说一次
- 只是当应用程序是前景(明确地不运行时,背景)
- 显然,如果你不必费心去关注应用程序的进出,那将会更加优雅
- 这个问题,我很惊讶,学习与
scheduleRepeating
重申,在模拟器,它保持运行时,应用程序是在后台:这并不让我有信心,它明确不会在后台运行 (一些?什么?)设备 - 这个问题,我发现在一台设备上testing尽可能多的代/操作系统,
scheduleRepeating
重复烦人地将 (只在一些情况下)运行一次,只有当应用程序进入后台。 也就是说,一旦应用程序进入后台,它将运行“一次”。 吸。
所以要重复一下:在iOS中,如何拥有一个每20秒运行一次的简单服务,并且只在应用程序处于前台运行时运行,并且它是无忧无虑的。理想情况下,您不必重新启动它,它或应用程序的生命中的任何东西…
真的做这么简单的事情最好的办法是什么?
这是我的(似乎)工作的解决scheme,这是不雅的。 当然有一个内置的方式,或者什么,在iOS做这样一个明显的事情?
open class SomeDaemon { static let shared = SomeDaemon() fileprivate init() { print("SomeDaemon is running") } var timer: DispatchSourceTimer? = nil let gap = 10 // seconds between runs func launch() { // you must call this from application#didLaunch // harmless if you accidentally call more than once // you DO NOT do ANYTHING on app pause/unpause/etc if timer != nil { print("SomeDaemon, timer running already") return } timer = DispatchSource.makeTimerSource(flags: [], queue: DispatchQueue.main) timer?.scheduleRepeating(deadline: .now(), interval: .seconds(gap)) timer?.setEventHandler{ self. doSomeThing() } timer?.resume() } private func doSomeThing() { if UIApplication.shared.applicationState != .active { print("avoided infuriating 'runs once more in bg' problem.") return } // actually do your thing here } }
幕后:
这不是华丽的 ,但它的作品相当不错。
struct ForegroundTimer { static var sharedTimerDelegate: ForegroundTimerDelegate? static var sharedTimer = Timer() private var timeInterval: Double = 20.0 static func startTimer() { ForegroundTimer.waitingTimer.invalidate() var wait = 0.0 if let time = ForegroundTimer.startedTime { wait = timeInterval - (Date().timeIntervalSince1970 - time).truncatingRemainder(dividingBy: Int(timeInterval)) } else { ForegroundTimer.startedTime = Date().timeIntervalSince1970 } waitingTimer = Timer.scheduledTimer(withTimeInterval: wait, repeats: false) { (timer) in ForegroundTimer.sharedTimerDelegate?.timeDidPass() ForegroundTimer.sharedTimer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: true, block: { (timer) in ForegroundTimer.sharedTimerDelegate?.timeDidPass() }) } } static func pauseTimer() { ForegroundTimer.sharedTimer.invalidate() } private static var startedTime: TimeInterval? private static var waitingTimer = Timer() } protocol ForegroundTimerDelegate { func timeDidPass() }
上面的代码已经可以使用了。 当然,你可以timeInterval
到任何你想要的时间间隔。
用法很简单:
在AppDelegate.swift中,有这两个方法:
func applicationDidBecomeActive(_ application: UIApplication) { ForegroundTimer.startTimer() } func applicationDidEnterBackground(_ application: UIApplication) { ForegroundTimer.pauseTimer() }
然后,有什么课程,你要“听”定时器实现ForegroundTimerDelegate
,它是必需的方法, timeDidPass()
。 最后,将该类/ self
分配给ForegroundTimer.sharedTimerDelegate
。 例如:
class ViewController: UIViewController, ForegroundTimerDelegate { func viewDidLoad() { ForegroundTimer.sharedTimerDelegate = self } func timeDidPass() { print("20 in-foreground seconds passed") } }
希望这可以帮助!
@ Dopapp的答案非常稳定,我会用它,但如果你想要它更简单,你可以尝试一下RunLoop:
let timer = Timer.scheduledTimer(withTimeInterval: wait, repeats: true) { _ in print("time passed") } RunLoop.current.add(timer, forMode: RunLoopMode.commonModes)
这甚至会给你一些关于后台执行的function。
警告:代码未经testing!