在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!