继续倒计时时,应用程序在后台运行/挂起



我有一个功能倒计时计时器。

问题是,当用户将应用程序放在后台时,我需要继续倒计时。或者暂停应用程序?我不知道该用什么术语来描述这一行动。

也就是说,用户打开应用程序,开始倒计时。用户应该能够使用其他应用程序,但倒计时仍然运行。此外,倒计时应该能够永远运行,直到它完成或当用户终止运行应用程序。

下面是我的定时器代码:

    class Timer{
var timer = NSTimer();
// the callback to be invoked everytime the timer 'ticks'
var handler: (Int) -> ();
//the total duration in seconds for which the timer should run to be set by the caller
let duration: Int;
//the amount of time in seconds elapsed so far
var elapsedTime: Int = 0;
var targetController = WaitingRoomController.self
var completionCallback: (() -> Void)!

/**
:param: an integer duration specifying the total time in seconds for which the timer should run repeatedly
:param: handler is reference to a function that takes an Integer argument representing the elapsed time allowing the implementor to process elapsed time and returns void
*/
init(duration: Int , handler : (Int) -> ()){
    self.duration = duration;
    self.handler = handler;
}
/**
Schedule the Timer to run every 1 second and invoke a callback method specified by 'selector' in repeating mode
*/
func start(){
    self.timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "onTick", userInfo: nil, repeats: true);
}
/**
invalidate the timer
*/
func stop(){
    println("timer was invaidated from stop()")
    timer.invalidate();
}

/**
Called everytime the timer 'ticks'. Keep track of the total time elapsed and trigger the handler to notify the implementors of the current 'tick'. If the amount of time elapsed is the same as the total duration for the timer was intended to run, stop the timer.
*/

@objc func onTick() {
    //println("onTick")
    //increment the elapsed time by 1 second
    self.elapsedTime++;
    //Notify the implementors of the updated value of elapsed time
    self.handler(elapsedTime);
    //If the amount of elapsed time in seconds is same as the total time in seconds for which this timer was intended to run, stop the timer
    if self.elapsedTime == self.duration {
        self.stop();
    }
}
deinit{
    println("timer was invalidated from deinit()")
    self.timer.invalidate();
}

}

我的建议是取消定时器并在应用程序进入后台时存储NSDate。你可以使用这个通知来检测应用程序进入后台:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "pauseApp", name: UIApplicationDidEnterBackgroundNotification, object: nil)

然后取消定时器并存储日期:

func pauseApp(){
    self.stop() //invalidate timer
    self.currentBackgroundDate = NSDate()
}

使用此通知检测用户返回:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "startApp", name: UIApplicationDidBecomeActiveNotification, object: nil)

然后计算从存储日期到当前日期的差值,更新计数器并再次启动计时器:

func startApp(){
    let difference = self.currentBackgroundDate.timeIntervalSinceDate(NSDate())
    self.handler(difference) //update difference
    self.start() //start timer
}

你不应该那样做。运行计时器使设备的处理器以全功率运行,这很糟糕。

只有某些类型的应用程序被允许在后台无限期运行代码,例如VOIP应用程序和音乐应用程序。

几个选项:

  1. 为将来的日期设置本地通知(这将向您的应用程序发送消息,或者在它不再运行时重新启动它)

  2. 当你启动计时器时,记录当前的NSDate。然后,当你的应用程序返回前台或重新启动时,将当前日期与保存日期进行比较,计算出经过的时间,并决定你的计时器是否已经完成。

试试这个…这段代码更新应用程序从后台/挂起和活动状态返回的时间。

类ProgressV: UIView {

var timer: NSTimer!
var expirationDate = NSDate()
//Set the time that you want to decrease..
var numSeconds: NSTimeInterval = 36000.0 // Ex:10:00 hrs
func startTimer()
{
    // then set time interval to expirationDate…
    expirationDate = NSDate(timeIntervalSinceNow: numSeconds)
    timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: #selector(updateUI(_:)), userInfo: nil, repeats: true)
    NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
}
func updateUI(timer: NSTimer)
{
  // Call the currentTimeString method which can decrease the time..
   let timeString = currentTimeString()
   labelName.text = timeString
}
func currentTimeString() -> String {
    let unitFlags: NSCalendarUnit = [.Hour, .Minute, .Second]
    let countdown: NSDateComponents = NSCalendar.currentCalendar().components(unitFlags, fromDate: NSDate(), toDate: expirationDate, options: [])
    var timeRemaining: String
    if countdown.hour > 0
    {
        timeRemaining = String(format: "%02d:%02d:%02d", countdown.hour, countdown.minute, countdown.second)
    }
    else {
        timeRemaining = String(format: "%02d:%02d:%02d", countdown.hour, countdown.minute, countdown.second)
    }
    return timeRemaining
}

}

确保在xCode中打开背景模式并设置所需的值。这是奇怪的,但即使后台模式被关闭,这段代码工作。在AppDelegate中设置application.beginBackgroundTask {}后,似乎可以工作任何计时器。

我使用以下代码:

在AppDelegate中添加代码:

func applicationDidEnterBackground(_ application: UIApplication) {
    application.beginBackgroundTask {} // allows to run background tasks
}

并在需要的地方调用下面的方法。

func registerBackgroundTask() {
    DispatchQueue.global(qos: .background).asyncAfter(deadline: DispatchTime.now() + 5, qos: .background) {
            print("fasdf")
        }
}

最新更新