在Swift中提供简单的服务,只保留前景吗?

Fat*_*tie 13 service ios swift3

我只是想要运行一些东西

  • 每说20秒
  • 只是当应用程序是前景时(显然不在后台运行)
  • 很明显,如果您不必费心跟随应用程序进出前景,那将会更加优雅
  • 这个问题,我很惊讶地了解到scheduleRepeating,在模拟器中,当应用程序处于后台时它会继续运行:这不能让我相信它明确地不会在后台运行(某些?什么?)设备
  • 这个问题,我发现一个设备上,尽可能多代/ OS测试成为可能,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
    }
}
Run Code Online (Sandbox Code Playgroud)

Dan*_*iel 4

幕后花絮:

它并不华丽,但效果非常好。

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()
}
Run Code Online (Sandbox Code Playgroud)

上面的代码可以按原样使用。当然,您可以timeInterval选择任何您想要的时间间隔。

用法很简单:

在 AppDelegate.swift 中,有以下两个方法:

func applicationDidBecomeActive(_ application: UIApplication) {
    ForegroundTimer.startTimer()
}

func applicationDidEnterBackground(_ application: UIApplication) {
    ForegroundTimer.pauseTimer()
}
Run Code Online (Sandbox Code Playgroud)

然后,让您想要“监听”计时器的任何类实现ForegroundTimerDelegate它所需的方法timeDidPass()。最后,将该 class/ 分配selfForegroundTimer.sharedTimerDelegate. 例如:

class ViewController: UIViewController, ForegroundTimerDelegate {
    func viewDidLoad() {
        ForegroundTimer.sharedTimerDelegate = self
    }

    func timeDidPass() {
        print("20 in-foreground seconds passed")
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助!