Swift中的简单服务,是否仍然存在,仅在前台? [英] Simple service in Swift, persists, foreground only?
问题描述
我只是想让某事运行
- 每说20秒
- 仅在应用程序为前台时显式显示(当后台运行时显式不运行)
- 很显然,如果您不必担心应用程序进入和退出前景,那会更加优雅
- 这个问题,我惊讶地发现
scheduleRepeating
,在模拟器中,当应用程序在后台运行时,它保持运行:这并没有使我确信它明确地显示了不会在某些设备上在后台运行 - 这个问题,我发现在尽可能多的世代/操作系统上进行测试的设备上,
scheduleRepeating
恼人的将(在某些情况下还是所有情况下)只能运行一次 当应用进入后台时.就是说:一旦应用程序进入后台,它就会再运行一次".吸.
- every say 20 seconds
- simply only when the app is foreground (explicitly not run when background)
- obviously, it would be more elegant if you don't have to bother following the app going in and out of foreground
- The issue, I was amazed to learn with
scheduleRepeating
that, in the simulator, it keeps running when the app is in background: that doesn't give me confidence that it explicitly won't run in background on (some? whatever?) devices - The issue, I discovered that on a device, testing with as many generations / OS as possible,
scheduleRepeating
annoyingly will (in some? all? cases) run one time only when the app goes into background. That is to say: it runs "one more time" once the app goes to background. Suck.
因此要重复一遍:在iOS中,如何有一个简单的服务每20秒运行一次,并且仅在应用程序处于前台时运行,并且没有大惊小怪..理想情况下,您无需重新启动在应用程序的生命周期中对其进行检查,检查或任何其他操作...
So to repeat: in iOS how to have a simple service that runs every 20 seconds, and, only runs when the app is in a foreground, and, it is fuss-free .. ideally you don't have to restart it, check it or anything during the life of the app...
真正做到这种简单事情的最佳方法是什么?
really what is the best way to do such a simple thing?
这是我的(看似)可行的解决方案,非常小巧.在iOS中肯定有一种内置的方式或类似的方式来做这种明显的事情?
This is my (seemingly) working solution, which is inelegant. Surely there is a built-in way, or something, to do such an obvious thing in 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
}
}
推荐答案
幕后:
它不是华丽的,但是效果很好.
Behind the scenes:
It isn't gorgeous, but it works pretty darn well.
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
设置为所需的任何时间间隔.
This code above is ready to use as-is. Of course you can timeInterval
to whatever time interval you want.
在AppDelegate.swift中,具有以下两种方法:
In AppDelegate.swift, have these two methods:
func applicationDidBecomeActive(_ application: UIApplication) {
ForegroundTimer.startTimer()
}
func applicationDidEnterBackground(_ application: UIApplication) {
ForegroundTimer.pauseTimer()
}
然后,具有您要针对计时器实现ForegroundTimerDelegate
进行监听"的任何类,并且它是必需的方法timeDidPass()
.最后,将该类/self
分配给ForegroundTimer.sharedTimerDelegate
.例如:
Then, have whatever class you want to 'listen' for the timer implement ForegroundTimerDelegate
, and it's required method, timeDidPass()
. Finally, assign that class/self
to ForegroundTimer.sharedTimerDelegate
. For example:
class ViewController: UIViewController, ForegroundTimerDelegate {
func viewDidLoad() {
ForegroundTimer.sharedTimerDelegate = self
}
func timeDidPass() {
print("20 in-foreground seconds passed")
}
}
希望这会有所帮助!
这篇关于Swift中的简单服务,是否仍然存在,仅在前台?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!