Swift 中的简单服务,持续存在,仅前台?



我只是想运行一些东西

  • 每说20秒
  • 仅当应用程序处于前台时(明确不在后台运行时运行(
  • 显然,如果您不必费心跟随应用程序进出前台,它会更优雅。
  • 这个问题,我很惊讶地scheduleRepeating了解到,在模拟器中,当应用程序在后台运行时,它会继续运行:这并不能让我相信它明确不会在后台运行(某些?
  • 这个问题,我发现在设备上,使用尽可能多的代/操作系统进行测试,scheduleRepeating烦人地(在某些情况下?所有?情况下(仅在应用程序进入后台时才运行一次。 也就是说:一旦应用程序进入后台,它就会"再运行一次"。吸。

所以重复一遍:在iOS中,如何拥有每20秒运行一次的简单服务,并且仅在应用程序处于前台时才运行,并且无需大惊小怪..理想情况下,您不必重新启动它,检查它或在应用程序的生命周期内进行任何事情...

做这么简单的事情,真的有什么最好的方法呢?

这是我(看似(有效的解决方案,这是不优雅的。肯定有一种内置的方法或其他东西可以在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)

这甚至会为您提供有关后台执行的一些功能。

警告:代码未测试!

相关内容

最新更新